Realmente me gustaría poder imprimir SQL válido para mi aplicación, incluidos los valores, en lugar de los parámetros de enlace, pero no es obvio cómo hacerlo en SQLAlchemy (por diseño, estoy bastante seguro).
¿Alguien ha resuelto este problema de manera general?
python
sqlalchemy
bukzor
fuente
fuente
sqlalchemy.engine
registro de SQLAlchemy . Registra consultas y parámetros de enlace, solo tendría que reemplazar los marcadores de posición de enlace con los valores en una cadena de consulta SQL fácilmente construida.Respuestas:
En la gran mayoría de los casos, la "cadena" de una declaración o consulta SQLAlchemy es tan simple como:
Esto se aplica tanto a un ORM
Query
como a cualquierselect()
otra declaración.Nota : la siguiente respuesta detallada se mantiene en la documentación de sqlalchemy .
Para obtener la declaración como compilada en un dialecto o motor específico, si la declaración en sí no está vinculada a una, puede pasar esto a compile () :
o sin motor:
Cuando se le da un
Query
objeto ORM , para obtener elcompile()
método solo necesitamos acceder primero al descriptor de acceso de declaración :con respecto a la estipulación original de que los parámetros vinculados deben "insertarse" en la cadena final, el desafío aquí es que SQLAlchemy normalmente no tiene la tarea de esto, ya que Python DBAPI lo maneja adecuadamente, sin mencionar que omitir los parámetros vinculados es probablemente los agujeros de seguridad más ampliamente explotados en las aplicaciones web modernas. SQLAlchemy tiene una capacidad limitada para hacer esta cadena en ciertas circunstancias, como la de emitir DDL. Para acceder a esta funcionalidad, se puede usar el indicador 'literal_binds', que se pasa a
compile_kwargs
:el enfoque anterior tiene la advertencia de que solo es compatible con tipos básicos, como ints y cadenas, y además, si
bindparam
se usa directamente un valor sin un valor preestablecido, tampoco podrá encadenar eso.Para admitir la representación literal en línea para los tipos no admitidos, implemente un
TypeDecorator
para el tipo de destino que incluye unTypeDecorator.process_literal_param
método:produciendo resultados como:
fuente
query.prettyprint()
. Alivia enormemente el dolor de depuración con grandes consultas.@compiles
, etc.) para cualquier cantidad de paquetes de terceros para implementar sistemas de impresión bonita.Esto funciona en python 2 y 3 y es un poco más limpio que antes, pero requiere SA> = 1.0.
Manifestación:
Da este resultado: (probado en python 2.7 y 3.4)
fuente
Dado que lo que desea tiene sentido solo al depurar, puede iniciar SQLAlchemy con
echo=True
, para registrar todas las consultas SQL. Por ejemplo:Esto también se puede modificar para una sola solicitud:
Si se usa con Flask, simplemente puede configurar
para obtener el mismo comportamiento.
fuente
flask-sqlalchemy
esta debería ser la respuesta aceptada.Podemos usar el método de compilación para este propósito. De los documentos :
Resultado:
Advertencia de documentos:
fuente
Entonces, basándose en los comentarios de @ zzzeek sobre el código de @ bukzor, se me ocurrió esto para obtener fácilmente una consulta "bastante imprimible":
Personalmente, me resulta difícil leer el código que no está sangrado, así que solía
sqlparse
reindentificar el SQL. Se puede instalar conpip install sqlparse
.fuente
datatime.now()
que usa Python 3 + sqlalchemy 1.0. Tendría que seguir los consejos de @zzzeek para crear un TypeDecorator personalizado para que funcione también.Este código se basa en la brillante respuesta existente de @bukzor. Acabo de agregar render personalizado para
datetime.datetime
escribir en OracleTO_DATE()
.Siéntase libre de actualizar el código para adaptarlo a su base de datos:
fuente
return "%s" % value
lugar dereturn repr(value)
en la sección float, int, long porque Python estaba produciendo longs como en22L
lugar de solo22
"STR_TO_DATE('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % value.strftime("%Y-%m-%d %H:%M:%S")
en mysqlMe gustaría señalar que las soluciones dadas anteriormente no "simplemente funcionan" con consultas no triviales. Un problema que encontré fue tipos más complicados, como pgsql ARRAY que causan problemas. Encontré una solución que, para mí, funcionó incluso con las matrices pgsql:
prestado de: https://gist.github.com/gsakkis/4572159
El código vinculado parece estar basado en una versión anterior de SQLAlchemy. Recibirá un error que dice que el atributo _mapper_zero_or_none no existe. Aquí hay una versión actualizada que funcionará con una versión más nueva, simplemente reemplace _mapper_zero_or_none con bind. Además, esto tiene soporte para matrices pgsql:
Probado en dos niveles de matrices anidadas.
fuente
from file import render_query; print(render_query(query))