У меня есть объект запроса SQLAlchemy, и я хочу получить текст скомпилированного оператора SQL со всеми его параметрами (например, никакие %s
или другие переменные, ожидающие связывания компилятором операторов или механизмом диалекта MySQLdb и т. Д.).
Вызов str()
запроса показывает что-то вроде этого:
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
Я пробовал искать в query._params, но это пустой dict. Я написал свой собственный компилятор, используя этот пример sqlalchemy.ext.compiler.compiles
декоратора, но даже там есть оператор, %s
где мне нужны данные.
Я не могу понять, когда мои параметры смешиваются для создания запроса; при изучении объекта запроса они всегда являются пустым словарем (хотя запрос выполняется нормально, и механизм его распечатывает, когда вы включаете регистрацию эха).
Я начинаю получать сообщение о том, что SQLAlchemy не хочет, чтобы я знал базовый запрос, поскольку он нарушает общий характер интерфейса API выражений для всех различных API-интерфейсов DB. Я не возражаю, если запрос будет выполнен до того, как я узнаю, что это было; Я просто хочу знать!
источник
c = q.statement.compile(...)
, ты можешь просто получитьc.params
as_scalar()
методаQuery
.str(q)
.В документации используется
literal_binds
для печати запроса сq
параметрами:В документации также содержится это предупреждение:
источник
Это должно работать с Sqlalchemy> = 0.6
источник
adapt
так. Как минимум, каждый раз вызывайте prepare () для возвращаемого значения, предоставляя соединение в качестве аргумента, чтобы он мог правильно цитировать.prepare
на возвращаемое значение , но , кажется , что он не имеет такой метод:AttributeError: 'psycopg2._psycopg.AsIs' object has no attribute 'prepare'
. Я использую psycopg2 2.2.1 BTWДля бэкэнда MySQLdb я немного изменил потрясающий ответ Альбертова (большое спасибо!). Я уверен, что их можно объединить, чтобы проверить, было ли
comp.positional
это,True
но это немного выходит за рамки этого вопроса.источник
return tuple(params)
работал как шарм! Вы сэкономили мне бесчисленные часы на чрезвычайно болезненном пути.Дело в том, что sqlalchemy никогда не смешивает данные с вашим запросом. Запрос и данные передаются отдельно в ваш базовый драйвер базы данных - интерполяция данных происходит в вашей базе данных.
Sqlalchemy передает запрос
str(myquery)
в базу данных, как вы видели , и значения будут помещены в отдельный кортеж.Вы можете использовать какой-то подход, в котором вы сами интерполируете данные с запросом (как предлагает Альбертов ниже), но это не то же самое, что выполняет sqlalchemy.
источник
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
ЭТО последний запрос. Они%s
отправляются в базу данных программой sqlalchemy - sqlalchemy НИКОГДА не помещает фактические данные вместо% ssqlalchemy.dialects.mysql.mysqldb
, выdo_executemany()
передаете инструкцию и параметры отдельно курсору MySQLdb. ура косвенное!Во-первых, позвольте мне предисловие, сказав, что я предполагаю, что вы делаете это в основном для целей отладки - я бы не рекомендовал пытаться изменить оператор вне SQLAlchemy fluent API.
К сожалению, не существует простого способа показать скомпилированный оператор с включенными параметрами запроса. SQLAlchemy фактически не помещает параметры в инструкцию - они передаются в ядро базы данных в виде словаря . Это позволяет библиотеке для конкретной базы данных обрабатывать такие вещи, как экранирование специальных символов, чтобы избежать внедрения SQL.
Но вы можете довольно легко сделать это в два этапа. Чтобы получить инструкцию, вы можете сделать, как вы уже показали, и просто распечатать запрос:
Вы можете приблизиться на один шаг с помощью query.statement, чтобы увидеть имена параметров. Обратите внимание:
:id_1
ниже и%s
выше - это не проблема в этом очень простом примере, но может быть ключевым в более сложном заявлении.Затем вы можете получить фактические значения параметров, получив
params
свойство скомпилированного оператора:По крайней мере, это сработало для серверной части MySQL; Я ожидал, что он также достаточно общий для PostgreSQL, и его не нужно использовать
psycopg2
.источник
Для серверной части postgresql, использующей psycopg2, вы можете прослушивать
do_execute
событие, а затем использовать курсор, оператор и параметры с принудительным вводом вместе сCursor.mogrify()
для встраивания параметров. Вы можете вернуть True, чтобы предотвратить фактическое выполнение запроса.Пример использования:
источник
Следующее решение использует язык выражений SQLAlchemy и работает с SQLAlchemy 1.1. Это решение не смешивает параметры с запросом (как было запрошено исходным автором), но предоставляет способ использования моделей SQLAlchemy для создания строк запроса SQL и словарей параметров для различных диалектов SQL. Пример основан на учебнике http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html.
Учитывая класс,
мы можем создать оператор запроса, используя функцию выбора .
Затем мы можем скомпилировать инструкцию в объект запроса.
По умолчанию оператор компилируется с использованием базовой «именованной» реализации, совместимой с базами данных SQL, такими как SQLite и Oracle. Если вам нужно указать диалект, например PostgreSQL, вы можете сделать
Или, если вы хотите явно указать диалект как SQLite, вы можете изменить стиль параметра с «qmark» на «named».
Из объекта запроса мы можем извлечь строку запроса и параметры запроса.
и, наконец, выполните запрос.
источник
Вы можете использовать события из семейства ConnectionEvents :
after_cursor_execute
илиbefore_cursor_execute
.В sqlalchemy UsageRecipes от @zzzeek вы можете найти этот пример:
Здесь вы можете получить доступ к своей выписке
источник
Итак, собрав множество маленьких кусочков этих разных ответов, я придумал то, что мне было нужно: простой набор кода, который нужно было вставлять и время от времени, но надежно (то есть обрабатывать все типы данных) получать точный скомпилированный SQL, отправленный на мой адрес. Серверная часть Postgres, просто запросив сам запрос:
источник
Я думаю, что .statement, возможно, поможет: http://docs.sqlalchemy.org/en/latest/orm/query.html?highlight=query
источник
Я создал эту небольшую функцию, которую импортирую, когда хочу распечатать полный запрос, учитывая, что я нахожусь в середине теста, когда диалект уже привязан:
источник