web-dev-qa-db-fra.com

différence entre les filtres à arguments multiples et les filtres de chaînes dans Django

Quelle est la différence entre un filtre à arguments multiples et un filtre de chaîne dans django?

52
testmobile

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.

42
Johnny Tsang

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.

15

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 dans Referenced: 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 |
                +------+--------+-------------+--------------+  

Dependenta1 fait référence à employeeA, et dependb1, b2references à 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. 

12
Grijesh Chauhan

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)
>>> 
6
DTing

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?

0
Tony Jasur

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)
0
Matt