J'ai un objet de requête SQLAlchemy et je veux obtenir le texte de l'instruction SQL compilée, avec tous ses paramètres liés (par exemple, aucune %s
ou d'autres variables en attente d'être liées par le compilateur d'instructions ou le moteur de dialecte MySQLdb, etc.).
L'appel str()
sur la requête révèle quelque chose comme ceci:
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
J'ai essayé de chercher dans query._params mais c'est un dict vide. J'ai écrit mon propre compilateur en utilisant cet exemple du sqlalchemy.ext.compiler.compiles
décorateur, mais même la déclaration contient toujours %s
où je veux des données.
Je ne peux pas vraiment comprendre quand mes paramètres sont mélangés pour créer la requête; lors de l'examen de l'objet de requête, il s'agit toujours d'un dictionnaire vide (bien que la requête s'exécute correctement et que le moteur l'imprime lorsque vous activez la journalisation d'écho).
Je commence à recevoir le message que SQLAlchemy ne veut pas que je connaisse la requête sous-jacente, car elle rompt la nature générale de l'interface de l'API d'expression avec toutes les différentes DB-API. Cela ne me dérange pas si la requête est exécutée avant que je découvre ce que c'était; Je veux juste savoir!
c = q.statement.compile(...)
, vous pouvez juste obtenirc.params
as_scalar()
méthode deQuery
.str(q)
.La documentation utilise
literal_binds
pour imprimer une requêteq
comprenant des paramètres:La documentation émet également cet avertissement:
la source
Cela devrait fonctionner avec Sqlalchemy> = 0.6
la source
adapt
de cette manière. Au minimum, appelez prepare () sur la valeur de retour de celui-ci à chaque fois, en fournissant la connexion comme argument, afin qu'il puisse faire des guillemets appropriés.prepare
sur la valeur de retour , mais est semble qu'il n'a pas cette méthode:AttributeError: 'psycopg2._psycopg.AsIs' object has no attribute 'prepare'
. J'utilise psycopg2 2.2.1 BTWPour le backend MySQLdb, j'ai un peu modifié la réponse géniale d'albertov (merci beaucoup!). Je suis sûr qu'ils pourraient être fusionnés pour vérifier si
comp.positional
c'était le cas ,True
mais cela dépasse légèrement la portée de cette question.la source
return tuple(params)
fonctionne comme un charme! Vous m'avez évité d'innombrables heures de devoir emprunter une route extrêmement pénible.Le fait est que sqlalchemy ne mélange jamais les données avec votre requête. La requête et les données sont transmises séparément à votre pilote de base de données sous-jacent - l'interpolation des données se produit dans votre base de données.
Sqlalchemy transmet la requête comme vous l'avez vu
str(myquery)
à la base de données, et les valeurs iront dans un tuple séparé.Vous pouvez utiliser une approche où vous interpolez vous-même les données avec la requête (comme albertov suggéré ci-dessous), mais ce n'est pas la même chose que sqlalchemy exécute.
la source
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
EST la dernière question. Ceux-ci%s
sont envoyés à la base de données par sqlalchemy - sqlalchemy ne met JAMAIS les données réelles à la place du% ssqlalchemy.dialects.mysql.mysqldb
,do_executemany()
transmet l'instruction et les paramètres séparément au curseur MySQLdb. yay indirection!Permettez-moi d'abord de dire que je suppose que vous faites cela principalement à des fins de débogage - je ne recommanderais pas d'essayer de modifier l'instruction en dehors de l'API SQLAlchemy fluent.
Malheureusement, il ne semble pas y avoir de moyen simple d'afficher l'instruction compilée avec les paramètres de requête inclus. SQLAlchemy ne met pas réellement les paramètres dans l'instruction - ils sont transmis au moteur de base de données sous forme de dictionnaire . Cela permet à la bibliothèque spécifique à la base de données de gérer des choses comme l'échappement des caractères spéciaux pour éviter l'injection SQL.
Mais vous pouvez le faire en deux étapes assez facilement. Pour obtenir l'instruction, vous pouvez faire comme vous l'avez déjà montré, et simplement imprimer la requête:
Vous pouvez faire un pas de plus avec query.statement, pour voir les noms des paramètres. Remarque
:id_1
ci-dessous vs%s
ci-dessus - pas vraiment un problème dans cet exemple très simple, mais pourrait être la clé dans une déclaration plus compliquée.Ensuite, vous pouvez obtenir les valeurs réelles des paramètres en obtenant la
params
propriété de l'instruction compilée:Cela a fonctionné pour un backend MySQL au moins; Je m'attendrais à ce que ce soit également assez général pour PostgreSQL sans avoir besoin d'utiliser
psycopg2
.la source
Pour le backend postgresql utilisant psycopg2, vous pouvez écouter l'
do_execute
événement, puis utiliser le curseur, l'instruction et le type de paramètres coercés avecCursor.mogrify()
pour incorporer les paramètres. Vous pouvez renvoyer True pour empêcher l'exécution réelle de la requête.Exemple d'utilisation:
la source
La solution suivante utilise le langage d'expression SQLAlchemy et fonctionne avec SQLAlchemy 1.1. Cette solution ne mélange pas les paramètres avec la requête (comme demandé par l'auteur d'origine), mais fournit un moyen d'utiliser les modèles SQLAlchemy pour générer des chaînes de requête SQL et des dictionnaires de paramètres pour différents dialectes SQL. L'exemple est basé sur le tutoriel http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html
Compte tenu de la classe,
nous pouvons produire une instruction de requête en utilisant la fonction de sélection .
Ensuite, nous pouvons compiler l'instruction dans un objet de requête.
Par défaut, l'instruction est compilée à l'aide d'une implémentation «nommée» de base compatible avec les bases de données SQL telles que SQLite et Oracle. Si vous devez spécifier un dialecte tel que PostgreSQL, vous pouvez faire
Ou si vous souhaitez spécifier explicitement le dialecte en tant que SQLite, vous pouvez changer le style de paramètre de «qmark» à «nommé».
À partir de l'objet de requête, nous pouvons extraire la chaîne de requête et les paramètres de requête
et enfin exécutez la requête.
la source
Vous pouvez utiliser les événements de la famille ConnectionEvents :
after_cursor_execute
oubefore_cursor_execute
.Dans sqlalchemy UsageRecipes by @zzzeek, vous pouvez trouver cet exemple:
Ici vous pouvez accéder à votre relevé
la source
Donc, en rassemblant beaucoup de petits morceaux de ces différentes réponses, j'ai trouvé ce dont j'avais besoin: un simple ensemble de code à insérer et de temps en temps mais de manière fiable (c'est-à-dire gère tous les types de données) saisir le SQL compilé exact envoyé à mon Postgres backend en interrogeant simplement la requête elle-même:
la source
Je pense que .statement ferait probablement l'affaire: http://docs.sqlalchemy.org/en/latest/orm/query.html?highlight=query
la source