Différence entre filter et filter_by dans SQLAlchemy

304

Quelqu'un pourrait-il expliquer la différence entre les fonctions filteret filter_bydans SQLAlchemy? Lequel devrais-je utiliser?

Bodacydo
la source

Réponses:

393

filter_by est utilisé pour les requêtes simples sur les noms de colonnes en utilisant des kwargs normaux, comme

db.users.filter_by(name='Joe')

La même chose peut être accomplie avec filter, sans utiliser kwargs, mais à la place en utilisant l'opérateur d'égalité '==', qui a été surchargé sur l'objet db.users.name:

db.users.filter(db.users.name=='Joe')

Vous pouvez également écrire des requêtes plus puissantes à l'aide filter, telles que des expressions comme:

db.users.filter(or_(db.users.name=='Ryan', db.users.country=='England'))

Daniel Velkov
la source
22
Comment ça marche sous le capot? N'évaluerait-il pas db.users.name=='Ryan'une fois à une constante et serait alors vide de sens à partir de là? Il semble que l'on aurait besoin d'utiliser un lambda pour que cela fonctionne.
Hamish Grubijan
46
l'opérateur d'égalité est surchargé
Daniel Velkov
9
type(model.column_name == 'asdf')sqlalchemy.sql.elements.BinaryExpression
Nick T
11
Soyez prudent lors de l'utilisation .filter. une requête comme id=12345, query(users).filter(id == id)ne filtrera pas users.id. Au lieu de cela, il évaluera id == idaussi Trueet retourner tous les utilisateurs. Vous devez utiliser .filter(users.id == id)(comme démontré ci-dessus). J'ai fait cette erreur un peu plus tôt dans la journée.
Nico Cernek du
118

En fait, nous les avons fusionnés à l'origine, c'est-à-dire qu'il y avait une méthode de type "filtre" qui acceptait *argset **kwargs, où vous pouviez passer une expression SQL ou des arguments de mots clés (ou les deux). En fait, je trouve cela beaucoup plus pratique, mais les gens ont toujours été confus, car ils surmontent généralement la différence entre column == expressionet keyword = expression. Nous les avons donc séparés.

zzzeek
la source
30
Je pense que votre point sur column == expressionvs keyword = expressionest le point clé à faire sur la différence entre filteret filter_by. Merci!
Hollister
2
Je suis nouveau dans sqlalchemy, alors excusez-moi si c'est une question stupide, mais filter_by () ne semble pas autoriser même les conditions très simples telles que "prix> = 100". Alors, pourquoi la fonction filter_by () fonctionne-t-elle de toute façon, si vous ne pouvez l'utiliser que pour la condition la plus simple telle que "prix = 100"?
PawelRoman
18
parce que les gens aiment ça
zzzeek
3
Y a-t-il une différence de performances entre eux? Je pensais que cela filter_bypourrait être un peu plus rapide que filter.
Devi
6
Le but de l'utilisation filter_byest de pouvoir écrire dans le nom du champ, pour cette classe, aucune question n'est posée - alors que flternécessite l'objet de colonne réel - qui nécessite généralement de taper (et de lire) au moins un nom de classe redondant. Donc, si l'on veut filtrer par égalité, c'est plutôt pratique.
jsbueno
36

filter_byutilise des arguments de mot-clé, tandis que filterpermet des arguments de filtrage pythonique commefilter(User.name=="john")

Johannes Charra
la source
34

C'est un sucre de syntaxe pour une écriture de requête plus rapide. Son implémentation en pseudocode:

def filter_by(self, **kwargs):
    return self.filter(sql.and_(**kwargs))

Pour ET, vous pouvez simplement écrire:

session.query(db.users).filter_by(name='Joe', surname='Dodson')

btw

session.query(db.users).filter(or_(db.users.name=='Ryan', db.users.country=='England'))

peut s'écrire

session.query(db.users).filter((db.users.name=='Ryan') | (db.users.country=='England'))

Vous pouvez également obtenir un objet directement par PK via la getméthode:

Users.query.get(123)
# And even by a composite PK
Users.query.get(123, 321)

Lors de l'utilisation de la getcasse, il est important que l'objet puisse être renvoyé sans demande de base de données à partir de identity maplaquelle peut être utilisé comme cache (associé à la transaction)

enomad
la source
Ces exemples de code sont trompeurs: les classes et les instances de table de base déclarative n'ont ni filtre ni méthode de requête; ils utilisent la session.
tortues sont mignonnes
Je reproduis users.filterde la réponse précédente. Et c'est peut-être de ma faute :) l' queryattribut est query_property et c'est un sucre assez standard de nos jours
enomad