Naprawdę chciałbym móc wydrukować prawidłowy kod SQL dla mojej aplikacji, w tym wartości, zamiast powiązać parametry, ale nie jest oczywiste, jak to zrobić w SQLAlchemy (z założenia, jestem prawie pewien).
Czy ktoś rozwiązał ten problem w sposób ogólny?
python
sqlalchemy
bukzor
źródło
źródło
sqlalchemy.engine
dziennika SQLAlchemy . Rejestruje zapytania i parametry wiązania, wystarczy zamienić symbole zastępcze powiązań na wartości z łatwo skonstruowanego ciągu zapytania SQL.Odpowiedzi:
W większości przypadków „stringification” instrukcji lub zapytania SQLAlchemy jest tak proste, jak:
Dotyczy to zarówno ORM,
Query
jak i każdegoselect()
innego oświadczenia.Uwaga : następująca szczegółowa odpowiedź jest przechowywana w dokumentacji sqlalchemy .
Aby otrzymać instrukcję skompilowaną do określonego dialektu lub silnika, jeśli sama instrukcja nie jest już powiązana z żadnym, możesz przekazać ją do metody compile () :
lub bez silnika:
Gdy otrzymamy
Query
obiekt ORM , aby uzyskać dostęp docompile()
metody, musimy najpierw uzyskać dostęp do metody dostępu .statement :jeśli chodzi o pierwotne zastrzeżenie, że powiązane parametry mają być „wstawiane” do końcowego ciągu, wyzwaniem jest tutaj to, że SQLAlchemy normalnie nie ma tego zadania, ponieważ jest to odpowiednio obsługiwane przez Python DBAPI, nie wspominając o pomijaniu powiązanych parametrów jest prawdopodobnie najczęściej wykorzystywane luki bezpieczeństwa w nowoczesnych aplikacjach internetowych. SQLAlchemy ma ograniczone możliwości wykonywania tego ciągu w pewnych okolicznościach, takich jak emisja DDL. Aby uzyskać dostęp do tej funkcjonalności, można użyć flagi „literal_binds” przekazanej do
compile_kwargs
:powyższe podejście ma zastrzeżenia, że jest obsługiwane tylko dla podstawowych typów, takich jak ints i stringi, a ponadto, jeśli a
bindparam
bez wstępnie ustawionej wartości jest używane bezpośrednio, nie będzie w stanie tego również określić.Aby obsługiwać renderowanie literału wbudowanego dla typów nieobsługiwanych, zaimplementuj a
TypeDecorator
dla typu docelowego, który zawieraTypeDecorator.process_literal_param
metodę:wytwarzanie wyników takich jak:
źródło
query.prettyprint()
. Niezwykle łagodzi problem związany z debugowaniem przy dużych zapytaniach.@compiles
itp.) dla dowolnej liczby pakietów firm trzecich, aby zaimplementować ładne systemy drukujące.Działa to w Pythonie 2 i 3 i jest nieco czystsze niż wcześniej, ale wymaga SA> = 1.0.
Próbny:
Daje to wyjście: (testowane w Pythonie 2.7 i 3.4)
źródło
Biorąc pod uwagę, że to, co chcesz, ma sens tylko podczas debugowania, możesz uruchomić SQLAlchemy z
echo=True
, aby rejestrować wszystkie zapytania SQL. Na przykład:Można to również zmodyfikować dla jednego żądania:
Jeśli jest używany z Flaskiem, możesz po prostu ustawić
uzyskać takie samo zachowanie.
źródło
flask-sqlalchemy
powinna być odpowiedzią akceptowaną.W tym celu możemy użyć metody kompilacji . Z dokumentów :
Wynik:
Ostrzeżenie od dokumentów:
źródło
Opierając się na komentarzach @ zzzeek do kodu @ bukzor, wymyśliłem to, aby łatwo uzyskać zapytanie „ładne do wydrukowania”:
Osobiście mam trudności z odczytaniem kodu, który nie jest wcięty, więc użyłem
sqlparse
ponownie kodu SQL. Można go zainstalować zpip install sqlparse
.źródło
datatime.now()
jednej, gdy używasz Pythona 3 + sqlalchemy 1.0. Musiałbyś postępować zgodnie z radą @ zzzeek dotyczącą tworzenia niestandardowego TypeDecorator, aby ten również działał.Ten kod jest oparty na genialnej istniejącej odpowiedzi od @bukzor. Właśnie dodałem niestandardowy render dla
datetime.datetime
typu do Oracle'sTO_DATE()
.Zapraszam do aktualizacji kodu, aby pasował do Twojej bazy danych:
źródło
return "%s" % value
zamiastreturn repr(value)
w sekcji typu float, int, long, ponieważ Python wyświetlał długie, a22L
nie tylko22
"STR_TO_DATE('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % value.strftime("%Y-%m-%d %H:%M:%S")
w mysqlZwracam uwagę, że powyższe rozwiązania nie „działają” tylko przy nietrywialnych zapytaniach. Jednym z problemów, na które się natknąłem, były bardziej skomplikowane typy, takie jak pgsql ARRAY powodujące problemy. Znalazłem rozwiązanie, które dla mnie działało nawet z pgsql ARRAY:
zapożyczone z: https://gist.github.com/gsakkis/4572159
Wydaje się, że powiązany kod jest oparty na starszej wersji SQLAlchemy. Pojawi się błąd informujący, że atrybut _mapper_zero_or_none nie istnieje. Oto zaktualizowana wersja, która będzie działać z nowszą wersją, po prostu zamień _mapper_zero_or_none na bind. Dodatkowo obsługuje to tablice pgsql:
Przetestowano na dwóch poziomach zagnieżdżonych tablic.
źródło
from file import render_query; print(render_query(query))