9
votes

En clause avec des entiers dans SQLALCHEMY / PSYCOPG2

Juste un débutant avec le combo Python / Postgres, alors pardonnez-moi si cela est trivial. J'exécute une requête SQL brute avec SQLalchemy le long des lignes de: xxx pré>

pour l'exemple ci-dessous j'ai essayé auto.Ids code> en tant que tuple contenant une chaîne ou des entiers ainsi qu'un tableau contenant des chaînes ou des entiers. De toute façon, il n'a pas fonctionné. P>

Lorsque j'utilise cette ligne: P>

TypeError: not all arguments converted during string formatting


0 commentaires

6 Réponses :


2
votes

Le % s espace réservé dans Exécuter attend un scalaire, pas un tuple. Vous devez soit remplacer par ','. Joindre ((% s ',) * len (myeuple)) ou utilisez la substitution de chaîne!


3 commentaires

Correction de la réponse, car la version originale produirait '%, s,%, s,%, s' .


Ce n'est pas correct: un seul % s La requête attend une séquence avec un seul élément.


C'est la solution que j'ai utilisée pour résoudre mon problème, merci. My Usecase: TAGS_TO_REMOVE = SET (['FOO', 'BAR']) DB.EXECTE ('Supprimer de l'article_Tags où l'article_id =? Et Tag_Name dans (% s)% (' , '.join (((('? ',) * Len (tags_to_remove))), article_id, * tags_remove)



0
votes

Si Self.Ids est une matrice, vous aurez un problème à faire la conversion dans la déclaration Exécute. Au lieu de cela, vous devez le faire comme une opération de chaîne avant d'appeler la déclaration exécutée.

Essayez ceci: p>

my_connection.execute('SELECT * FROM public.table WHERE pk_table_id IN (%s)' % 
                      ",".join(str(x) for x in self.ids))


9 commentaires

Remarque: l'appel donné à rejoindre nécessiterait les identifiants dans self.Ids pour être des chaînes.


Non, ce ne serait pas. Python utilise% s pour toutes les substitutions variables.


Bien sûr, passant int s sur % s Les paramètres de formatage de chaîne fonctionneraient, mais str.join () n'est pas si libéral. Essayez ','. Joindre (plage (10)) dans une coque Python.


Pas de problème du tout: ",". Joindre ([str (x) pour x dans la plage (10)])


Votre appel à rejoindre dans votre réponse suppose que les éléments de autodons sont des chaînes, d'où mon commentaire original.


pas quand j'utilise la compréhension de la liste. Ils sont tous transformés en chaînes maintenant.


AVERTISSEMENT: JAMAIS, JAMAIS NE JAMAIS Utilisez la concaténation de la cordes Python (+) ou des paramètres de chaîne Interpolation (%) pour passer des variables à une chaîne de requête SQL. Pas même à des armes à feu.


Je veux juste répéter ce qui précède. Cette réponse suggère une approche que la documentation PSYCOPG va de grandes longueurs pour admonester ses utilisateurs à ne jamais, jamais, car cela crée un trou de sécurité béant.


Quel est le trou de sécurité? Ce n'est qu'un trou de sécurité si Self.ID vient de l'utilisateur, pas si vous le générez vous-même.



7
votes

J'ai fini par la fossé Sqlalchemy pour le droit Psycopg2, donc je ne sais pas si cela s'applique à 100%. Ce que j'ai découvert, c'était que Psycopg2 compilera correctement la clause dans la clause si vous le transmettez un tuple plutôt que d'une matrice / liste. J'ai passé un tuple d'entiers et ça a bien fonctionné.


2 commentaires

Merci, cela fonctionne très bien. Au lieu d'utiliser params = [liste] il faut utiliser params = [tuple (liste)]


+1 - Voir aussi les documents: initd.org/ psycopg / docs / ...



7
votes

Vous pouvez utiliser le CUR.Mogrify Méthode: XXX


3 commentaires

N'oubliez pas de fermer votre curseur cur.close ()


Je ne pense pas que vous devez utiliser cur.mogrify à l'intérieur du cur.execute , cela fonctionne directement dans la méthode Execute


@Anentropic si cela fonctionne alors c'est une nouvelle version. Si vous voulez dire par des œuvres que vous utilisez le signe de%, vous introduisez une préoccupation de sécurité et j'espère que vous ne voulez pas dire cela!



2
votes

Si vos identifiants sont dans une liste, vous pouvez utiliser la liste d'adaptation de la liste: xxx

extrait de list-adaptation


0 commentaires

0
votes

cur.execute (requête, vars = aucun) s'attend à Variables (l'accent sur le pluriel) à y être transmis.

Lorsque vous passez un seul paramètre qui est ITABLE : une liste, une chaîne ou, dans ce cas, un tuple, ce paramètre doit être enveloppé comme un tuple sinon la fonction exécuter la fonction interprète comme Les paramètres multiples étant passés, même si la requête n'attend que un paramètre, d'où l'erreur pas tous les arguments convertis (accent sur le pluriel).

Le correctif général est de Toujours do cur.execute (requête, vars = (var1,) . Il est utile de spécifier le mot-clé vars pour vous rappeler que la fonction s'attend à ce que la fonction s'attend à ce que la fonction s'attend à ce que la fonction s'attend à ce que la fonction s'attend à ce que la fonction s'attend à ce que la fonction s'attend à ce que la fonction s'attend à des arguments .

La solution spécifique dans ce cas est xxx


0 commentaires