Mam obiekt zapytania SQLAlchemy i chcę uzyskać tekst skompilowanej instrukcji SQL ze wszystkimi powiązanymi parametrami (np. Brak %s
lub inne zmienne oczekujące na powiązanie przez kompilator instrukcji lub silnik dialektu MySQLdb itp.).
Wywołanie str()
zapytania ujawnia coś takiego:
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
Próbowałem szukać w query._params, ale jest to pusty dykt. Napisałem swój własny kompilator, korzystając z tego przykładu sqlalchemy.ext.compiler.compiles
dekoratora, ale nawet stwierdzenie tam nadal zawiera %s
dane.
Nie mogę się do końca dowiedzieć, kiedy moje parametry są mieszane, aby utworzyć zapytanie; podczas badania obiektu zapytania są one zawsze pustym słownikiem (chociaż zapytanie wykonuje się dobrze, a silnik wypisuje je po włączeniu logowania echa).
Zaczynam otrzymywać komunikat, że SQLAlchemy nie chce, żebym znało zapytanie, ponieważ łamie on ogólny charakter interfejsu API wyrażeń we wszystkich różnych DB-API. Nie mam nic przeciwko, jeśli zapytanie zostanie wykonane, zanim dowiem się, co to było; Chcę po prostu wiedzieć!
źródło
c = q.statement.compile(...)
, możesz po prostu dostaćc.params
as_scalar()
-metodyQuery
.str(q)
.Dokumentacja używa
literal_binds
do wydrukowania zapytanieq
łącznie z parametrami:Dokumentacja zawiera również to ostrzeżenie:
źródło
To powinno działać z Sqlalchemy> = 0,6
źródło
adapt
w ten sposób. Przynajmniej za każdym razem wywołaj funkcję ready () na zwracanej z niej wartości, podając połączenie jako argument, aby mógł wykonać odpowiednie cytowanie.prepare
na wartości zwracanej ale wydaje się, że nie ma tej metody:AttributeError: 'psycopg2._psycopg.AsIs' object has no attribute 'prepare'
. Używam psycopg2 2.2.1 BTWDla zaplecza MySQLdb zmodyfikowałem trochę niesamowitą odpowiedź Alberta (dzięki wielkie!). Jestem pewien, że można je scalić, aby sprawdzić, czy
comp.positional
było,True
ale to nieco wykracza poza zakres tego pytania.źródło
return tuple(params)
działała jak urok! Zaoszczędziłeś mi niezliczonych godzin jazdy po wyjątkowo bolesnej drodze.Rzecz w tym, że sqlalchemy nigdy nie miesza danych z zapytaniem. Zapytanie i dane są przekazywane oddzielnie do podstawowego sterownika bazy danych - interpolacja danych odbywa się w bazie danych.
Sqlalchemy przekazuje zapytanie
str(myquery)
do bazy danych, tak jak widzieliśmy , a wartości zostaną umieszczone w osobnej krotce.Możesz użyć jakiegoś podejścia, w którym sam interpolujesz dane za pomocą zapytania (jak zasugerował albertov poniżej), ale to nie to samo, co wykonuje sqlalchemy.
źródło
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
JEST ostatecznym pytaniem. Są%s
one wysyłane do bazy danych przez sqlalchemy - sqlalchemy NIGDY nie umieszcza rzeczywistych danych w miejscu% ssqlalchemy.dialects.mysql.mysqldb
,do_executemany()
przekazuje instrukcję i parametry osobno do kursora MySQLdb. yay indirection!Najpierw pozwolę sobie powiedzieć, że zakładam, że robisz to głównie w celu debugowania - nie polecałbym próbować modyfikować instrukcji poza API płynnym SQLAlchemy.
Niestety wydaje się, że nie ma prostego sposobu na pokazanie skompilowanej instrukcji z dołączonymi parametrami zapytania. SQLAlchemy w rzeczywistości nie umieszcza parametrów w instrukcji - są one przekazywane do silnika bazy danych jako słownik . Dzięki temu biblioteka specyficzna dla bazy danych może obsługiwać takie rzeczy, jak unikanie znaków specjalnych w celu uniknięcia wstrzyknięcia SQL.
Ale możesz to zrobić w dwuetapowym procesie dość łatwo. Aby uzyskać wyciąg, możesz zrobić to, co już pokazałeś i po prostu wydrukować zapytanie:
Możesz podejść o krok bliżej dzięki query.statement, aby zobaczyć nazwy parametrów. Uwaga
:id_1
poniżej i%s
powyżej - nie jest to problem w tym bardzo prostym przykładzie, ale może być kluczowy w bardziej skomplikowanym stwierdzeniu.Następnie możesz uzyskać rzeczywiste wartości parametrów, pobierając
params
właściwość skompilowanej instrukcji:To działało przynajmniej dla zaplecza MySQL; Spodziewałbym się, że jest również wystarczająco ogólny dla PostgreSQL bez konieczności używania
psycopg2
.źródło
Dla zaplecza postgresql używającego psycopg2, możesz nasłuchiwać
do_execute
zdarzenia, a następnie użyć kursora, instrukcji i wpisać wymuszone parametry wraz zCursor.mogrify()
wbudowanymi parametrami. Możesz zwrócić True, aby zapobiec faktycznemu wykonaniu zapytania.Przykładowe użycie:
źródło
Poniższe rozwiązanie używa języka SQLAlchemy Expression Language i współpracuje z SQLAlchemy 1.1. To rozwiązanie nie miesza parametrów z zapytaniem (zgodnie z żądaniem pierwotnego autora), ale zapewnia sposób używania modeli SQLAlchemy do generowania ciągów zapytań SQL i słowników parametrów dla różnych dialektów SQL. Przykład jest oparty na samouczku http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html
Biorąc pod uwagę klasę,
możemy utworzyć instrukcję zapytania za pomocą funkcji select .
Następnie możemy skompilować instrukcję do obiektu zapytania.
Domyślnie instrukcja jest kompilowana przy użyciu podstawowej „nazwanej” implementacji, która jest zgodna z bazami danych SQL, takimi jak SQLite i Oracle. Jeśli potrzebujesz określić dialekt, taki jak PostgreSQL, możesz to zrobić
Lub jeśli chcesz jawnie określić dialekt jako SQLite, możesz zmienić styl parametru z „qmark” na „named”.
Z obiektu zapytania możemy wyodrębnić ciąg zapytania i parametry zapytania
i na koniec wykonaj zapytanie.
źródło
Możesz użyć zdarzeń z rodziny ConnectionEvents :
after_cursor_execute
lubbefore_cursor_execute
.W sqlalchemy UsageRecipes autorstwa @zzzeek można znaleźć następujący przykład:
Tutaj możesz uzyskać dostęp do swojego wyciągu
źródło
Tak więc, łącząc wiele małych fragmentów tych różnych odpowiedzi, wymyśliłem to, czego potrzebowałem: prosty zestaw kodu do wrzucenia i czasami, ale niezawodnie (tj. Obsługuje wszystkie typy danych), pobieram dokładny, skompilowany kod SQL wysłany do mojego Backend Postgres, po prostu odpytując samo zapytanie:
źródło
Myślę, że .statement prawdopodobnie załatwi sprawę: http://docs.sqlalchemy.org/en/latest/orm/query.html?highlight=query
źródło