2008-10-08

Как использовать в словаре русские строки

Андрей Орлов  2008-10-08 13:01

Словарь в Zope3 используется, в основном, для создания интерфейсов с полями, допускающих выбор из нескольких возможных значений (такие поля отображаются в формах как выпадающие списки). Существует готовая реализация словаря SimpleVocabulary, позволяющая легко создавать словари просто перечислив их содержимое. Однако из-за ряда неточностей, как в реализации полей схем, так и в реализации самого SimpleVocabulary возникают трудности при использовании его со строками unicode (или utf-8). Эта статья рассказывает о причинах возникновения и способе решения проблемы.

Как использовать SimpleVocabulary с строками в unicode

Как использовать SimpleVocabulary с строками в unicode

Подробно работа со словарями описана в статье Руководство по использованию словарей. Там же приведено много примеров использования класса SimpleVocabulary.

Класс SimpleVocabulary это практически готовый к использованию словарь, который сильно облегчает программирование под Zope3. К сожалению, существует ряд неточностей в реализации полей интерфейсов, использующих словари, виджетов и самого словаря, из-за которых простая конструкция:

from zope.schema.vocabulary import SimpleVocabulary
vocabulary = SimpleVocabulary.fromValues([u"раз",u"два"])

оказывается неработоспособной в случае использования строк unicode: русские слова не могут быть использованы в формах с элементами выбора, т.к. выбор любого русского слова считается ошибкой.

Почему

Чтобы объяснить причины этого явления, напомним, что словарь состоит из термов, каждый из которых включает в себя токен, значение и заголовок элемента словаря. Токен - это то, что идентифицирует терм. При использовании конструкции, указанной выше, терм создается при помощи SimpleTerm, который создает токен из значения приведением его к строке:

term.token = str(value)

Это вполне срабатывает даже при наличии национальных символов, при условии что вы установили utf-8 кодировкой по умолчанию для самого языка питон.

Однако, при последующей работе, при сохранении форм не происходит преобразования в строку значения, полученного из формы. Поэтому сравнение с токеном завершается ложным результатом (сравнивается одна и та же строка в unicode и в utf-8): иными словами, форма не находит в словаре введенное значение.

Как бороться

Внимательное изучение кодов показало, что адекватный метод решение проблемы - явный вызов SimpleTerm и самостоятельное преобразование к уникальной форме, не содержащей символов, кроме ascii:

from zope.schema.vocabulary import SimpleVocabulary,SimpleTerm

vocabulary = SimpleVocabulary(
      [ SimpleTerm(x,token="".join(
        ["%04x" % ord(y) for y in list(unicode(x))]),
        title=x
        ) for x in [u"Раз",u"Два"] ]
)

Обратите внимание, что в этом случае пришлось указать еще и title: иначе поле формы будет выведено значение токена. Такая конструкция сразу же начинает работать, хотя с прикладной точки зрения почти ничего не изменилось.

Заключение

Для того, чтобы облегчить жизнь пользователям Zope3, в библиотеку ng.lib-0.0.6 включена исправленная (несколько иным образом) версия SimpleVocabulary.

Ссылки на эту статью:

Вышел ng.lib-0.0.6
Официальный сайт Zope3 Московская группа изучения реактивного движения The Dream Bot Site noooxml