J'aimerais vraiment pouvoir imprimer du SQL valide pour mon application, y compris des valeurs, plutôt que des paramètres de liaison, mais ce n'est pas évident de le faire dans SQLAlchemy (de par sa conception, j'en suis assez sûr).
Quelqu'un at-il résolu ce problème de manière générale?
python
sqlalchemy
Bukzor
la source
la source
sqlalchemy.engine
journal de SQLAlchemy . Il enregistre les requêtes et les paramètres de liaison, il vous suffit de remplacer les espaces réservés de liaison par les valeurs d'une chaîne de requête SQL facilement construite.Réponses:
Dans la grande majorité des cas, la "stringification" d'une instruction ou d'une requête SQLAlchemy est aussi simple que:
Cela s'applique à la fois à un ORM
Query
et à touteselect()
instruction ou autre.Remarque : la réponse détaillée suivante est maintenue dans la documentation de sqlalchemy .
Pour obtenir l'instruction compilée dans un dialecte ou un moteur spécifique, si l'instruction elle-même n'est pas déjà liée à un, vous pouvez la transmettre à compile () :
ou sans moteur:
Lorsqu'on lui donne un
Query
objet ORM , pour accéder à lacompile()
méthode, il suffit d'accéder d' abord à l' accesseur .statement :en ce qui concerne la stipulation d'origine selon laquelle les paramètres liés doivent être "intégrés" dans la chaîne finale, le défi ici est que SQLAlchemy n'est normalement pas chargé de cela, car cela est géré de manière appropriée par le Python DBAPI, sans parler du contournement des paramètres liés. probablement les failles de sécurité les plus largement exploitées dans les applications Web modernes. SQLAlchemy a une capacité limitée à effectuer cette stringification dans certaines circonstances telles que l'émission de DDL. Pour accéder à cette fonctionnalité, on peut utiliser le drapeau 'literal_binds', passé à
compile_kwargs
:l'approche ci-dessus a la mise en garde qu'elle n'est prise en charge que pour les types de base, tels que les ints et les chaînes, et de plus si un
bindparam
sans valeur prédéfinie est utilisé directement, il ne pourra pas non plus le stringify.Pour prendre en charge le rendu littéral en ligne pour les types non pris en charge, implémentez un
TypeDecorator
pour le type cible qui inclut uneTypeDecorator.process_literal_param
méthode:produisant une sortie comme:
la source
query.prettyprint()
. Cela facilite considérablement le débogage avec les grosses requêtes.@compiles
, etc.) pour n'importe quel nombre de packages tiers pour implémenter de jolis systèmes d'impression.Cela fonctionne en python 2 et 3 et est un peu plus propre qu'avant, mais nécessite SA> = 1.0.
Démo:
Donne cette sortie: (testé en python 2.7 et 3.4)
la source
Étant donné que ce que vous voulez n'a de sens que lors du débogage, vous pouvez démarrer SQLAlchemy avec
echo=True
, pour enregistrer toutes les requêtes SQL. Par exemple:Cela peut également être modifié pour une seule demande:
S'il est utilisé avec Flask, vous pouvez simplement définir
pour obtenir le même comportement.
la source
flask-sqlalchemy
cela devrait être la réponse acceptée.Nous pouvons utiliser la méthode de compilation à cet effet. À partir de la documentation :
Résultat:
Avertissement de la documentation:
la source
Donc, en me basant sur les commentaires de @ zzzeek sur le code de @ bukzor, j'ai trouvé ceci pour obtenir facilement une requête "assez imprimable":
sqlparse
Personnellement, j'ai du mal à lire du code qui n'est pas indenté, j'ai donc l'habitude de réindenter le SQL. Il peut être installé avecpip install sqlparse
.la source
datatime.now()
celle lors de l'utilisation de python 3 + sqlalchemy 1.0. Vous devrez suivre les conseils de @zzzeek sur la création d'un TypeDecorator personnalisé pour que celui-ci fonctionne également.Ce code est basé sur la brillante réponse existante de @bukzor. Je viens d'ajouter un rendu personnalisé pour le
datetime.datetime
type dans OracleTO_DATE()
.N'hésitez pas à mettre à jour le code en fonction de votre base de données:
la source
return "%s" % value
au lieu dereturn repr(value)
dans la section float, int, long parce que Python produisait des longs comme22L
au lieu de juste22
"STR_TO_DATE('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % value.strftime("%Y-%m-%d %H:%M:%S")
dans mysqlJe tiens à souligner que les solutions données ci-dessus ne "fonctionnent pas seulement" avec des requêtes non triviales. Un problème que j'ai rencontré était des types plus compliqués, tels que les ARRAY pgsql causant des problèmes. J'ai trouvé une solution qui, pour moi, fonctionnait même avec les ARRAY pgsql:
emprunté à: https://gist.github.com/gsakkis/4572159
Le code lié semble être basé sur une ancienne version de SQLAlchemy. Vous obtiendrez une erreur indiquant que l'attribut _mapper_zero_or_none n'existe pas. Voici une version mise à jour qui fonctionnera avec une version plus récente, il vous suffit de remplacer _mapper_zero_or_none par bind. De plus, cela prend en charge les tableaux pgsql:
Testé à deux niveaux de tableaux imbriqués.
la source
from file import render_query; print(render_query(query))