Eu realmente gostaria de poder imprimir SQL válido para o meu aplicativo, incluindo valores, em vez de parâmetros de ligação, mas não é óbvio como fazer isso no SQLAlchemy (por design, tenho certeza).
Alguém resolveu esse problema de uma maneira geral?
python
sqlalchemy
Bukzor
fonte
fonte
sqlalchemy.engine
log do SQLAlchemy . Ele registra consultas e parâmetros de ligação, você apenas precisará substituir os espaços reservados de ligação pelos valores em uma sequência de consulta SQL prontamente construída.Respostas:
Na grande maioria dos casos, a "stringification" de uma instrução ou consulta SQLAlchemy é tão simples quanto:
Isso se aplica tanto a um ORM
Query
quanto a qualquerselect()
outra declaração.Nota : a resposta detalhada a seguir está sendo mantida na documentação do sqlalchemy .
Para obter a instrução compilada em um dialeto ou mecanismo específico, se a própria declaração ainda não estiver vinculada a uma, você pode passar para compile () :
ou sem um motor:
Quando é fornecido um
Query
objeto ORM , para obter ocompile()
método, precisamos acessar apenas o acessador .statement primeiro:No que diz respeito à estipulação original de que os parâmetros vinculados devem ser "incorporados" na sequência final, o desafio aqui é que o SQLAlchemy normalmente não é encarregado disso, pois isso é tratado adequadamente pelo DBAPI do Python, sem mencionar que os parâmetros vinculados são ignorados. provavelmente as falhas de segurança mais amplamente exploradas em aplicativos da web modernos. O SQLAlchemy possui capacidade limitada para fazer essa stringificação em determinadas circunstâncias, como a de emitir DDL. Para acessar essa funcionalidade, pode-se usar o sinalizador 'literal_binds', passado para
compile_kwargs
:a abordagem acima tem as ressalvas de que ele é suportado apenas para tipos básicos, como ints e strings, e além disso, se um valor
bindparam
sem um valor pré-definido for usado diretamente, também não será possível especificá-lo.Para oferecer suporte à renderização literal embutida para tipos não suportados, implemente a
TypeDecorator
para o tipo de destino que inclui umTypeDecorator.process_literal_param
método:produzindo saída como:
fonte
query.prettyprint()
. Facilita imensamente a dor da depuração com grandes consultas.@compiles
, etc.) para qualquer número de pacotes de terceiros para implementar sistemas de impressão bonita.Isso funciona em python 2 e 3 e é um pouco mais limpo do que antes, mas requer SA> = 1.0.
Demo:
Dá esta saída: (testado em python 2.7 e 3.4)
fonte
Dado que o que você deseja faz sentido apenas durante a depuração, você pode iniciar o SQLAlchemy com
echo=True
, para registrar todas as consultas SQL. Por exemplo:Isso também pode ser modificado para apenas uma única solicitação:
Se usado com o Flask, você pode simplesmente definir
para obter o mesmo comportamento.
fonte
flask-sqlalchemy
deve ser a resposta aceita.Podemos usar o método de compilação para esse fim. Dos documentos :
Resultado:
Aviso dos documentos:
fonte
Então, com base nos comentários de @ zzzeek no código de @ bukzor, eu vim com isso para obter facilmente uma consulta "bastante imprimível":
Pessoalmente, tenho dificuldade em ler o código que não é recuado, então eu costumava
sqlparse
reindentar o SQL. Pode ser instalado compip install sqlparse
.fonte
datatime.now()
aquele ao usar python 3 + sqlalchemy 1.0. Você teria que seguir o conselho do @ zzzeek sobre como criar um TypeDecorator personalizado para que ele funcionasse também.Esse código é baseado na resposta brilhante existente de @bukzor. Acabei de adicionar renderização personalizada para o
datetime.datetime
tipo no OracleTO_DATE()
.Sinta-se livre para atualizar o código para se adequar ao seu banco de dados:
fonte
return "%s" % value
em vez dereturn repr(value)
no float, int, longa seção porque Python foi a saída de longs como22L
em vez de apenas22
"STR_TO_DATE('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % value.strftime("%Y-%m-%d %H:%M:%S")
no mysqlGostaria de salientar que as soluções fornecidas acima não "apenas funcionam" com consultas não triviais. Um problema que encontrei foram tipos mais complicados, como ARRAYs do pgsql, causando problemas. Eu encontrei uma solução que, para mim, funcionou mesmo com ARRAYs do pgsql:
emprestado de: https://gist.github.com/gsakkis/4572159
O código vinculado parece basear-se em uma versão mais antiga do SQLAlchemy. Você receberá um erro dizendo que o atributo _mapper_zero_or_none não existe. Aqui está uma versão atualizada que funcionará com uma versão mais recente; você simplesmente substitui _mapper_zero_or_none por bind. Além disso, isso tem suporte para matrizes pgsql:
Testado para dois níveis de matrizes aninhadas.
fonte
from file import render_query; print(render_query(query))