4 мая 2009 г.

Несколько баз данных в SQLAlchemy и наследование

Как я писал ранее, в SQLAlchemy есть средства для работы с нескольким базами. Первая проблема, с которой я столкнулся — автоматический выбор соединения перестаётся работать для моделей с наследованием. Дело в том, что метод get_bind() сессии делает поиск соединения с нашем словаре на основе атрибута mapped_table маппера объекта. Для обычных моделей это объект класса Table, на основе которого я и строил словарь с соединениями. Но для производных классов при использовании joined table inheritance это объект класса Join для нескольких таблиц. На самом деле выбор соединения для запросов (каковым объект Join и является) в SQLAlchemy реализован, но почему-то не используется для моделей. Во избежание переписывания всего метода get_bind() я просто передал mapped_table вторым аргументом:
class DBSession(sqlalchemy.orm.session.Session):

    def get_bind(self, mapper, clause=None):
        if mapper is not None and clause is None:
            c_mapper = sqlalchemy.orm.util._class_to_mapper(mapper)
            if hasattr(c_mapper, 'mapped_table'):
                clause = mapper.mapped_table
        return sqlalchemy.orm.session.Session.get_bind(self, mapper, clause)

3 комментария:

Baloo комментирует...

Уважаемый Денис!
Может быть, Вы подскажете, ни форум, ни отправка трэйсбэка ине не помогли.
Дело вот чем:
Используем SQLAlchemy, инструкцию LIKE - (пробовал все три последних версии). База - Firebird. Пробовал 2.0 и 2.1, думаю, что проблема все-таки в SQLAlchemy. ОС - WinXP SP2, Python-драйвер под FireBird - последний KinterBasDB (Предпоследний тоже пробовал).
Код контроллера:
contracts_q = meta.Session.query(Contracts)
##contracts = contracts_q.filter_by(nunitcode='0') ##без филиалов
contracts = contracts_q.filter(and_(Contracts.nunitcode =='0', Contracts.ncont.like('%'+ncont+'%'),
Contracts.contract.like('%'+contract+'%')))
c.paginator = paginate.Page(
contracts,
page = page,
items_per_page=20,
url_args = c.url_args,
)
return render('contracts/list.mako')

Вот отрывок из MAKO-шаблона:

${h.form(h.url_for(controller='contracts', action='search'), method="get")}
Поиск:
№ договора: ${h.text(name='ncont', required=True, size=4, maxlength=4)}
Наименование: ${h.text(name='contract', required=True, size=40, maxlength=120)}
${h.submit(value=u"Поиск", name='submit')}
${h.end_form()}

Поле Ncont в базе (тип Varchar) имеет длину 4 символа. База в кодировке Win-1251. Если отрабатываем в поле поиска для столбца Contracts.Ncont что-либо больше 2-х символов, имеем :
⇝ ProgrammingError: (ProgrammingError) (-802L, "String overflow: value 5 bytes long cannot fit in character field of maximum length 4 (value is '%123%').") 'SELECT count(1) AS count_1 \nFROM "CONTRACTS" \nWHERE "CONTRACTS".nunitcode = ? AND "CONTRACTS".ncont LIKE ? AND "CONTRACTS".contract LIKE ?' ['0', u'%123%', u'%%']
Понятно, что добавляя символы % по бокам, мы имеем уже 5 символов. Но и что? При чем тут длина поля? Пробовал из командной строки, минуя SQLAlchemy, с помощью лишь инструкций Kinterbasdb - все нормально! То-есть, проблема только в SQLAlchemy.
Отказаться от нее? Но мне нравится, как быстро она работает с паджинатором, пробовал паджинировать без нее (инструкция ROW) - долго. Всякий раз идет полный запрос на сервере.
Спасибо, Денис. (В смысле - я тоже Денис)

Unknown комментирует...

В этом комментарии явно недостаточно информации для того, чтобы понять, в чём проблема. Да и место для обсуждения неудачное - комментарий явно не в тему. Хорошее место для решения таких проблем, например, Stack Overflow или Google группа sqlalchemy. В крайнем случае можно было бы дать ссылку на тот форум, где вы уже пытались обсудить этот вопрос.

Baloo комментирует...

http://python.su/forum/viewtopic.php?id=4489
Вот ссылка. В группу Google тоже писал, ответов 0