Quelle est la différence entre un filtre à arguments multiples et un filtre de chaîne dans django?
Comme vous pouvez le constater dans les instructions SQL générées, la différence n'est pas le "OU" comme certains pourraient le penser. C'est ainsi que sont placés WHERE et JOIN.
Exemple1 (même table jointe): from https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Blog.objects.filter(
entry__headline__contains='Lennon',
entry__pub_date__year=2008)
Cela vous donnera tous les blogs qui ont une entrée one avec les deux (entry__headline__contains='Lennon') AND (entry__pub_date__year=2008)
, ce que vous êtes en droit d’attendre de cette requête.
Résultat:
Blog with {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}
Exemple 2 (chaîné)
Blog.objects.filter(
entry__headline__contains='Lennon'
).filter(
entry__pub_date__year=2008)
Cela couvrira tous les résultats de l'exemple 1, mais générera un peu plus de résultat. Parce qu’il filtre d’abord tous les blogs avec (entry__headline__contains='Lennon')
, puis des filtres de résultat (entry__pub_date__year=2008)
.
La différence est que cela vous donnera également des résultats comme:
Un seul blog avec plusieurs entrées
{entry.headline: '**Lennon**', entry.pub_date: 2000},
{entry.headline: 'Bill', entry.pub_date: **2008**}
Lorsque le premier filtre a été évalué, le livre est inclus en raison de la première entrée (même si d'autres entrées ne correspondent pas). Lorsque le deuxième filtre est évalué, le livre est inclus en raison de la deuxième entrée.
Une table: Mais si la requête ne comporte pas de tables jointes comme dans l'exemple de Yuji et DTing. Le résultat est identique.
La plupart du temps, il n'y a qu'un seul ensemble de résultats possible pour une requête.
L’utilisation des filtres de chaînage vient avec m2m:
Considère ceci:
# will return all Model with m2m field 1
Model.objects.filter(m2m_field=1)
# will return Model with both 1 AND 2
Model.objects.filter(m2m_field=1).filter(m2m_field=2)
# this will NOT work
Model.objects.filter(Q(m2m_field=1) & Q(m2m_field=2))
D'autres exemples sont les bienvenus.
Le cas dans lequel les résultats de "arguments multiples filtre-requête" est différent de "chaîné-filtre-requête", comme suit:
La sélection d'objets référencés sur la base d'objets et de relations de référencement est un à plusieurs (ou plusieurs à plusieurs).
Filtres multiples:
Referenced.filter(referencing1_a=x, referencing1_b=y) # same referencing model ^^ ^^
Filtres chaînés:
Referenced.filter(referencing1_a=x).filter(referencing1_b=y)
Les deux requêtes peuvent générer un résultat différent:
Si plus d'un les lignes de referenceencing-modelReferencing1
peuvent se référer à la même ligne de modeled-referenceReferenced
. Cela peut être le cas dansReferenced
:Referencing1
ont soit 1: N (un à plusieurs) ou N: M (plusieurs à plusieurs) relation.
Exemple:
Considérons que mon application my_company
a deux modèles Employee
et Dependent
. Un employé dans my_company
peut avoir plus de personnes à charge (en d'autres termes, une personne à charge peut être le fils/fille d'un seul employé, alors qu'un employé peut avoir plus d'un fils/fille).
Ehh, en supposant que mari et femme ne puissent pas travailler dans un my_company
. J'ai pris 1: m exemple
Ainsi, Employee
est un modèle référencé qui peut être référencé par plus de Dependent
qui correspond à un modèle. Considérons maintenant l'état de relation comme suit:
Employee: Dependent: +------+ +------+--------+-------------+--------------+ | name | | name | E-name | school_mark | college_mark | +------+ +------+--------+-------------+--------------+ | A | | a1 | A | 79 | 81 | | B | | b1 | B | 80 | 60 | +------+ | b2 | B | 68 | 86 | +------+--------+-------------+--------------+
Dependent
a1
fait référence à employeeA
, et dependb1, b2
references à employeeB
.
Maintenant ma requête est:
Trouver tous les employés dont le fils/la fille a des marques de distinction (disons> = 75%) à la fois au collège et à l’école?
>>> Employee.objects.filter(dependent__school_mark__gte=75,
... dependent__college_mark__gte=75)
[<Employee: A>]
La sortie est 'A' dépendante 'a1' a des marques de distinction à la fois au collège et l'école dépend de l'employé 'A'. Remarque 'B' n'est pas sélectionné, car l'enfant de 'B' des enfants de bas âge a des marques de distinction à la fois à l'université et à l'école. Algèbre relationnelle:
Employé ⋈(school_mark> = 75 AND college_mark> = 75)Dépendant
En second lieu, j'ai besoin d'une requête:
Trouvez tous les employés dont certaines des personnes à charge ont des marques de distinction au collège et à l’école?
>>> Employee.objects.filter(
... dependent__school_mark__gte=75
... ).filter(
... dependent__college_mark__gte=75)
[<Employee: A>, <Employee: B>]
Cette fois, "B" a également été sélectionné car "B" a deux enfants (plus d'un!), L'un a la marque de distinction à l'école "b1" et l'autre est une marque de distinction au collège "b2".
L'ordre du filtre importe peu, nous pouvons également écrire la requête ci-dessus comme suit:
>>> Employee.objects.filter(
... dependent__college_mark__gte=75
... ).filter(
... dependent__school_mark__gte=75)
[<Employee: A>, <Employee: B>]
le résultat est identique! L'algèbre relationnelle peut être:
(Employé ⋈(school_mark> = 75)Dépendant) ⋈(college_mark> = 75)Dépendant
Notez ce qui suit:
dq1 = Dependent.objects.filter(college_mark__gte=75, school_mark__gte=75)
dq2 = Dependent.objects.filter(college_mark__gte=75).filter(school_mark__gte=75)
Résultat identique: [<Dependent: a1>]
Je vérifie la requête SQL cible générée par Django en utilisant print qd1.query
et print qd2.query
sont les mêmes (Django 1.6).
Mais sémantiquement, les deux sont différents de moi. d'abord ressemble à une simple section σ[school_mark> = 75 ET college_mark> = 75](Dépendant) et deuxième comme requête imbriquée lente: σ[school_mark> = 75](σ[college_mark> = 75](Dépendant)).
Si besoin est Code @codepad
au fait, il est donné dans la documentation @ Une relation à valeurs multiples Je viens d'ajouter un exemple, je pense que cela sera utile pour quelqu'un de nouveau.
Vous pouvez utiliser le module de connexion pour afficher les requêtes SQL brutes à comparer. Comme expliqué par Yuji, pour la plupart, ils sont équivalents comme indiqué ici:
>>> from Django.db import connection
>>> samples1 = Unit.objects.filter(color="orange", volume=None)
>>> samples2 = Unit.objects.filter(color="orange").filter(volume=None)
>>> list(samples1)
[]
>>> list(samples2)
[]
>>> for q in connection.queries:
... print q['sql']
...
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
>>>
Si nécessite a et b alors
and_query_set = Model.objects.filter(a=a, b=b)
si nécessite un aussi bien que b alors
chaied_query_set = Model.objects.filter(a=a).filter(b=b)
Documents officiels: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Related Post: Chaînage de plusieurs filtres () dans Django, s'agit-il d'un bogue?
Si vous vous retrouvez sur cette page à chercher comment créer de manière dynamique un ensemble de requêtes Django avec plusieurs filtres de chaînage, mais que ces filtres doivent être du type AND
au lieu de OR
, envisagez d'utiliser Q objets .
Un exemple:
# First filter by type.
filters = None
if param in CARS:
objects = app.models.Car.objects
filters = Q(tire=param)
Elif param in PLANES:
objects = app.models.Plane.objects
filters = Q(wing=param)
# Now filter by location.
if location == 'France':
filters = filters & Q(quay=location)
Elif location == 'England':
filters = filters & Q(harbor=location)
# Finally, generate the actual queryset
queryset = objects.filter(filters)