Я действительно хотел бы иметь возможность распечатывать действительный SQL для моего приложения, включая значения, а не параметры привязки, но не совсем очевидно, как это сделать в SQLAlchemy (в принципе, я уверен в этом).
Кто-нибудь решил эту проблему в общем виде?
python
sqlalchemy
bukzor
источник
источник
sqlalchemy.engine
журнал SQLAlchemy . Он регистрирует запросы и параметры привязки, вам нужно всего лишь заменить заполнители привязки значениями в готовой строке запроса SQL.Ответы:
В подавляющем большинстве случаев «строковое преобразование» оператора или запроса SQLAlchemy так же просто, как:
Это относится как к ORM,
Query
так и к любомуselect()
или другому утверждению.Примечание : следующий подробный ответ сохраняется в документации по sqlalchemy .
Чтобы получить инструкцию как скомпилированную для определенного диалекта или движка, если сама инструкция еще не связана с какой-либо из них, вы можете передать это в compile () :
или без двигателя:
Когда нам передается
Query
объект ORM , для того, чтобы получитьcompile()
доступ к методу, нам нужен только доступ к аксессору .statement :Что касается первоначального условия, что связанные параметры должны быть «встроены» в окончательную строку, то здесь проблема состоит в том, что SQLAlchemy обычно не выполняет эту задачу, поскольку это обрабатывается соответствующим образом DBAPI Python, не говоря уже о том, что обход связанных параметров вероятно, наиболее широко используемые дыры в безопасности в современных веб-приложениях. SQLAlchemy имеет ограниченные возможности для выполнения этой последовательности при определенных обстоятельствах, таких как испускание DDL. Чтобы получить доступ к этой функции, можно использовать флаг literal_binds, передаваемый
compile_kwargs
:у вышеупомянутого подхода есть предостережения, что он поддерживается только для базовых типов, таких как целые и строковые, и, кроме того, если
bindparam
напрямую используется без предварительно заданного значения, он также не сможет это упорядочить.Для поддержки встроенного рендеринга литералов для типов, которые не поддерживаются, реализуйте
TypeDecorator
для целевого типа, который включаетTypeDecorator.process_literal_param
метод:производя продукцию как:
источник
query.prettyprint()
. Это облегчает боль отладки с большими запросами безмерно.@compiles
и т. д.) для любого количества сторонних пакетов для реализации систем симпатичной печати.Это работает в python 2 и 3 и немного чище, чем раньше, но требует SA> = 1.0.
Демо-версия:
Дает этот вывод: (проверено в Python 2.7 и 3.4)
источник
Учитывая, что то, что вы хотите, имеет смысл только при отладке, вы можете запустить SQLAlchemy
echo=True
для регистрации всех запросов SQL. Например:Это также может быть изменено только для одного запроса:
Если вы используете Flask, вы можете просто установить
чтобы получить такое же поведение.
источник
flask-sqlalchemy
этого должен быть принятый ответ.Мы можем использовать метод компиляции для этой цели. Из документов :
Результат:
Предупреждение из документов:
источник
Поэтому, опираясь на комментарии @zzzeek к коду @ bukzor, я придумал это, чтобы легко получить «симпатичный для печати» запрос:
Лично мне трудно читать код, который не имеет отступов, поэтому я использовал
sqlparse
для переиндексации SQL. Может быть установлен сpip install sqlparse
.источник
datatime.now()
одного, при использовании python 3 + sqlalchemy 1.0. Вы должны последовать совету @ zzzeek по созданию пользовательского TypeDecorator, чтобы он тоже работал.Этот код основан на блестящем существующем ответе @bukzor. Я просто добавил пользовательский рендер для
datetime.datetime
типа в OracleTO_DATE()
.Не стесняйтесь обновлять код в соответствии с вашей базой данных:
источник
return "%s" % value
вместоreturn repr(value)
секции float, int, long, потому что Python22L
22
"STR_TO_DATE('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % value.strftime("%Y-%m-%d %H:%M:%S")
в MySQLЯ хотел бы отметить, что приведенные выше решения не «просто работают» с нетривиальными запросами. Одна проблема, с которой я столкнулся, была более сложные типы, такие как pgsql ARRAYs, вызывающие проблемы. Я нашел решение, которое для меня, просто работает даже с массивами pgsql:
заимствовано из: https://gist.github.com/gsakkis/4572159
Похоже, что связанный код основан на более старой версии SQLAlchemy. Вы получите сообщение о том, что атрибут _mapper_zero_or_none не существует. Вот обновленная версия, которая будет работать с более новой версией, вы просто замените _mapper_zero_or_none на bind. Кроме того, здесь есть поддержка массивов pgsql:
Проверено на двух уровнях вложенных массивов.
источник
from file import render_query; print(render_query(query))