Saya benar-benar ingin dapat mencetak SQL yang valid untuk aplikasi saya, termasuk nilai-nilai, daripada mengikat parameter, tetapi tidak jelas bagaimana melakukan ini dalam SQLAlchemy (secara desain, saya cukup yakin).
Adakah yang memecahkan masalah ini secara umum?
python
sqlalchemy
bukzor
sumber
sumber
sqlalchemy.engine
log SQLAlchemy . Ini mencatat kueri dan mengikat parameter, Anda hanya perlu mengganti placeholder mengikat dengan nilai-nilai pada string kueri SQL yang dibuat dengan mudah.Jawaban:
Dalam sebagian besar kasus, "pengetatan" dari pernyataan atau permintaan SQLAlchemy semudah:
Ini berlaku baik untuk ORM
Query
maupunselect()
pernyataan apa pun atau lainnya.Catatan : jawaban terinci berikut dijaga pada dokumentasi sqlalchemy .
Untuk mendapatkan pernyataan yang dikompilasi ke dialek atau mesin tertentu, jika pernyataan itu sendiri belum terikat dengan yang Anda bisa melewati ini untuk mengkompilasi () :
atau tanpa mesin:
Saat diberi
Query
objek ORM , untuk mendapatkancompile()
metode ini, kita hanya perlu mengakses .statement accessor terlebih dahulu:berkenaan dengan ketentuan asli bahwa parameter terikat harus "digariskan" ke dalam string terakhir, tantangan di sini adalah bahwa SQLAlchemy biasanya tidak ditugaskan dengan ini, karena ini ditangani dengan tepat oleh Python DBAPI, belum lagi melewati parameter terikat adalah mungkin lubang keamanan yang paling banyak dieksploitasi dalam aplikasi web modern. SQLAlchemy memiliki kemampuan terbatas untuk melakukan pengetatan ini dalam keadaan tertentu seperti memancarkan DDL. Untuk mengakses fungsi ini, seseorang dapat menggunakan bendera 'literal_binds', diteruskan ke
compile_kwargs
:pendekatan di atas memiliki peringatan bahwa itu hanya didukung untuk tipe dasar, seperti int dan string, dan lebih jauh lagi jika
bindparam
tanpa nilai yang telah ditetapkan sebelumnya digunakan secara langsung, itu tidak akan dapat untuk mengikat itu juga.Untuk mendukung rendering literal sebaris untuk tipe yang tidak didukung, terapkan a
TypeDecorator
untuk tipe target yang mencakupTypeDecorator.process_literal_param
metode:menghasilkan output seperti:
sumber
query.prettyprint()
. Ini memudahkan rasa sakit debugging dengan pertanyaan besar.@compiles
, dll.) untuk sejumlah paket pihak ketiga untuk menerapkan sistem pencetakan yang cantik.Ini berfungsi dalam python 2 dan 3 dan sedikit lebih bersih dari sebelumnya, tetapi membutuhkan SA> = 1.0.
Demo:
Memberikan output ini: (diuji dengan python 2.7 dan 3.4)
sumber
Mengingat bahwa apa yang Anda inginkan hanya masuk akal ketika debugging, Anda dapat memulai SQLAlchemy dengan
echo=True
, untuk mencatat semua permintaan SQL. Sebagai contoh:Ini juga dapat dimodifikasi hanya untuk satu permintaan:
Jika digunakan dengan Flask, Anda cukup mengatur
untuk mendapatkan perilaku yang sama.
sumber
flask-sqlalchemy
ini harus jawaban yang diterima.Kita dapat menggunakan metode kompilasi untuk tujuan ini. Dari dokumen :
Hasil:
Peringatan dari dokumen:
sumber
Jadi, membangun komentar @zzzeek pada kode @ bukzor, saya membuat ini untuk dengan mudah mendapatkan permintaan "cukup-cetak":
Saya pribadi mengalami kesulitan membaca kode yang tidak berlekuk jadi saya sudah terbiasa
sqlparse
dengan reindent SQL. Dapat diinstal denganpip install sqlparse
.sumber
datatime.now()
menggunakan python 3 + sqlalchemy 1.0. Anda harus mengikuti saran @zzzeek tentang cara membuat TypeDecorator khusus agar bisa berfungsi juga.Kode ini didasarkan pada jawaban brilian yang ada dari @bukzor. Saya baru saja menambahkan render khusus untuk
datetime.datetime
tipe ke OracleTO_DATE()
.Jangan ragu untuk memperbarui kode yang sesuai dengan basis data Anda:
sumber
return "%s" % value
alih-alihreturn repr(value)
di bagian float, int, long karena Python menghasilkan long sebagai22L
ganti hanya22
"STR_TO_DATE('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % value.strftime("%Y-%m-%d %H:%M:%S")
dalam mysqlSaya ingin menunjukkan bahwa solusi yang diberikan di atas tidak "hanya bekerja" dengan pertanyaan non-sepele. Satu masalah yang saya temui adalah jenis yang lebih rumit, seperti pgsql ARRAY yang menyebabkan masalah. Saya menemukan solusi untuk saya, hanya bekerja dengan pgsql ARRAYs:
dipinjam dari: https://gist.github.com/gsakkis/4572159
Kode tertaut tampaknya didasarkan pada versi SQLAlchemy yang lebih lama. Anda akan mendapatkan pesan kesalahan yang mengatakan bahwa atribut _mapper_zero_or_none tidak ada. Berikut ini adalah versi yang diperbarui yang akan bekerja dengan versi yang lebih baru, Anda cukup mengganti _mapper_zero_or_none dengan bind. Selain itu, ini memiliki dukungan untuk array pgsql:
Diuji untuk dua level array bersarang.
sumber
from file import render_query; print(render_query(query))