У меня есть функция, которую я добавил как обратный вызов before_execute для SQLAlchemy, например:
event.listen(self.app_engine, "before_execute", self.before_exec)
В этом обратном вызове я пытаюсь извлечь строковое представление оператора, который должен быть выполнен. Я узнал, что это не совсем тривиально - похоже, проблема заключается в запросах на основе ORM, а не в базовых, которые работают.
При компиляции запросов на основе ORM я сталкиваюсь с ошибками, подобными следующим:
sqlalchemy.exc.CompileError: Bind parameter 'widget_id' without a renderable value not allowed here.
Аргумент multiparams для before_execute заполняется для запроса ORM, но не для основного запроса. Поэтому я попытался сделать следующее:
clauseelement.values(**multiparams[0][0]).compile(compile_kwargs={"literal_binds": True})
Но, к сожалению, это просто приводит к:
sqlalchemy.exc.CompileError: Unconsumed column names: widget_id
Я не могу понять, как параметры сохраняются или обрабатываются, особенно когда вы добавляете слой в ORM. Я прочитал некоторые источники SQLAlchemy и все, что я могу найти в Интернете, но мне не очень повезло.
Вот большой контекст кода, который не работает:
def before_exec(self, conn, clauseelement, multiparams, params):
if not isinstance(clauseelement, (dml.Delete, dml.Update)):
return
query = select([clauseelement.table])
if clauseelement._whereclause is not None:
query = query.where(clauseelement._whereclause)
stmt_redo = clauseelement.compile(compile_kwargs={"literal_binds": True})
Основной стиль запроса, который работает:
self.session.query(Widget).filter_by(name="Foo").update({"name": "Baz"})
Запрос на основе ORM, который не работает:
widget = self.session.query(Widget).filter_by(name="Foo").first()
widget.name = "Baz"
self.session.add(widget)
self.session.commit()
Спасибо за ваше время!