2009-12-11

Pylons, SQLAlchemy, кодировка

Долгие мучения с вышеуказанной связкой побудили меня написать эту заметку.

Работа с SQLite не вызывала проблем, т.к. эта СУБД хранит данные в Unicode, и Pylons+mako по умолчанию с ним отлично работают. Просмотр данных в SQLite можно делать с помощью:
1) консольной утилиты (sudo apt-get install sqlite3)
2) SQLite Database browser (sudo apt-get install sqlitebrowser)
3) плагином для Firefox (http://code.google.com/p/sqlite-manager/)
Все они нормально отображают данные, без крякозябрей. На web-страницы шаблонизатор mako также выводит все корректно.

А вот с MySQL дело несколько сложнее, т.к. он может отдавать данные в разных кодировках. Чтобы получить данные в нужной, а не в той, что стоит в настройках сервера по умолчанию (они располагаются в /etc/mysql/my.cnf), нужно дать команду "SET NAMES кодировка".
Моя история была такова, что потребовалось данные из одной БД, которую использовала CMS Joomla, перетащить в другую, чтобы работать с ней из Pylons. Как я понял, Joomla при работе с БД использовала "SET NAMES latin1", что для англоязычных товарищей - нормально и привычно уже много лет. И все бы ничего, да есть засада.
Программы для работы с MySQL, которые я использую в основном, это:
1) MySQL Query Browser (sudo apt-get install mysql-query-browser)
2) phpMyAdmin на сервере
Эти приложения по умолчанию предпочитают кодировку соединения UTF8. Поэтому, что в одном, что в другом кириллица была видна как "ПеÑ". Есть приложения, которые справляются с этой проблемой, но в phpMyAdmin на сервере этого не исправишь.
Так что-же делать? Перевести данные из одной кодировки в другую. Мне пришлось написать скрипт, который создает два соединения с MySQL, причем в первом устанавливаю "SET NAMES latin1" (для донорской базы), во втором "SET NAMES utf8" (для новой). Остается пройтись по записям, считывая их в latin1 и записывая в utf8.
После такой обработки вышеприведенные программы отображают кириллицу как полагается. Остается только настроить Pylons и SQLAlchemy.
Итак, для корректного отображения данных нужно дать серверу MySQL команду "SET NAMES utf8". Где же это сделать? Я нашел три варианта. Предположим, проект называется app.
1) Файл /app/config/environment.py, метод load_environment
from sqlalchemy import engine_from_config
from app.model import init_model
def load_environment(global_conf, app_conf):
    engine = engine_from_config(config, 'sqlalchemy.')
    engine.execute("SET NAMES utf8")
    init_model(engine)
2) Файл /app/model/__init__.py, метод init_model
def init_model(engine):
    engine.execute("SET NAMES utf8")
В обоих случаях, при старте проекта в консоли будет видно, что эти команды выполняются. И все вроде бы пошло гладко! Но это до поры. А именно, до поры создания нового соединения.
Как известно, SQLAlchemy использует так называемый pool, т.е. некий список соединений, который использует по мере занятости, циклически. Их колличество можно менять. Пока я этого не понял, неоднократно был удивляем странным поведением пилонов. Так вот, пока хватает одного соединения, все идет как задумано, но стоит перейти на второе - косяки, вперед! "SET NAMES" для них никто не задавал, поэтому кодировка будет "как получится", а именно знаками вопросов для кириллицы. Вот тут то и пригодится третий способ. Он задает команду при создании соединения, и все pool-ы будут передавать данные с нужной кодировкой. Почитать об этом больше можно тут.
3) Файл /development.ini
sqlalchemy.url = mysql://root:@localhost:3306/church?init_command=set%20names%20%22utf8%22
sqlalchemy.convert_unicode=true
sqlalchemy.encoding='utf8'

Теперь немного о причине таких махинаций. Только таким образом мне удалось добиться того, чтобы поиск русских слов в базе данных происходил без учета регистра. В SQLite он не работает, т.к. там Unicode, и выбирать не приходится. И только в MySQL, и с данными в utf8 это получилось. Кстати, со словами, состоящими из латинских символов, проблем нет. Если есть другие способы, буду рад добавить их.

2009-12-08

Pylons и mako: Почему метод контроллера у меня вызывается дважды?

Записка на память. Ситуация:
Метод контроллера при варианте

return "ABC"

отрабатывает один раз.
При варианте

return render("/abc.mako")

метод вызывается дважды. Но не во всех шаблонах.
Причина: наличие в шаблоне строки

<link rel="stylesheet" type="text/css" href="/" media="all">

Pylons пытается подгрузить по ссылке содержимое. Если ничего не указано, то он обращается к тому же контроллеру и тому же методу, откуда вызван рендер шаблона. Стилей он там не находит, но метод срабатывает. В результате лишняя нагрузка, и ненужная деятельность.

2009-12-07

Программа для изучения Библии в Linux. Опрос.

Изначально программа для изучения Библии в ОС Linux задумывалась исключительно для этих целей. Никаких там посторонних, хоть и христианских, книжек, никаких песен или комментариев. И, пока что, так оно и остается.
Но, наконец-то братья откликнулись, и в комментариях было высказано предложение добавить возможность работы с модулями "Цитаты" Тимофея Ха либо напрямую, либо конвертировать их в формат моей разработки. Я размышляю над этим, и при возможности, займусь.
А пока что, мне было бы интересно, какие переводы Священного Писания вы считаете востребованными? Для меня RST и KJV более чем достаточно. Хотелось бы еще Женевскую учебную Библию добавить, но ее я в модулях Цитаты не нашел, а то обязательно бы прикрутил.
Прошу отписываться по этому поводу.

P.S. - самая актуальная версия - по ссылке справа вверху.