it-swarm.com.de

unterschied zwischen Filter mit mehreren Argumenten und Kettenfilter in Django

Was ist der Unterschied zwischen einem Filter mit mehreren Argumenten und einem Kettenfilter in Django?

52
testmobile

Wie Sie in den generierten SQL-Anweisungen sehen können, ist der Unterschied nicht das "ODER", wie manche vermuten. So wird WO und JOIN platziert.

Beispiel1 (gleiche verknüpfte Tabelle): aus https://docs.djangoproject.com/de/dev/topics/db/queries/#spanning-multi-valued-relationships

Blog.objects.filter(
       entry__headline__contains='Lennon', 
       entry__pub_date__year=2008)

Dadurch erhalten Sie alle Blogs, die one mit beiden (entry__headline__contains='Lennon') AND (entry__pub_date__year=2008)-Einträgen haben. Dies ist, was Sie von dieser Abfrage erwarten würden. 

Ergebnis:

Blog with {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}

Beispiel 2 (verkettet)

Blog.objects.filter(
       entry__headline__contains='Lennon'
           ).filter(
       entry__pub_date__year=2008)

Dies deckt alle Ergebnisse aus Beispiel 1 ab, erzeugt jedoch etwas mehr Ergebnis. Weil es zuerst alle Blogs mit (entry__headline__contains='Lennon') und dann aus den Ergebnisfiltern (entry__pub_date__year=2008) filtert.

Der Unterschied ist, dass es Ihnen auch Ergebnisse gibt wie:

Ein einzelner Blog mit mehreren Einträgen 

{entry.headline: '**Lennon**', entry.pub_date: 2000}, 
{entry.headline: 'Bill', entry.pub_date: **2008**}

Wenn der erste Filter ausgewertet wurde, wird das Buch aufgrund des ersten Eintrags einbezogen (obwohl es andere Einträge gibt, die nicht übereinstimmen). Wenn der zweite Filter ausgewertet wird, ist das Buch aufgrund des zweiten Eintrags enthalten. 

Eine Tabelle: Wenn die Abfrage jedoch keine verknüpften Tabellen enthält, wie im Beispiel von Yuji und DTing. Das Ergebnis ist dasselbe.

42
Johnny Tsang

Der Fall, in dem sich die Ergebnisse der "Filterabfrage mit mehreren Argumenten" von den Ergebnissen der "Filterabfrage mit verketteten Argumenten" unterscheiden:

Die Auswahl von referenzierten Objekten auf der Basis von referenzierten Objekten und Beziehungen erfolgt Eins-zu-Viele (oder Viele-zu-Viele).

Mehrere Filter:

    Referenced.filter(referencing1_a=x, referencing1_b=y)
    #  same referencing model   ^^                ^^

Verkettete Filter:

    Referenced.filter(referencing1_a=x).filter(referencing1_b=y)

Beide Abfragen können unterschiedliche Ergebnisse ausgeben:
Wenn mehr als eine Zeile in ReferenzmodellReferencing1 auf dieselbe Zeile in ReferenzmodellReferenced verweisen kann. Dies kann der Fall sein in Referenced: Referencing1 haben entweder 1: N (eins zu viele) oder N: M (viele zu viele) Beziehung.

Beispiel:

Betrachten Sie meine Anwendung my_company hat zwei Modelle Employee und Dependent. Ein Mitarbeiter in my_company kann mehr als Abhängige haben (mit anderen Worten, ein Abhängiger kann ein Sohn/eine Tochter eines einzelnen Mitarbeiters sein, während ein Mitarbeiter mehr als einen Sohn/eine Tochter haben kann).
Äh, vorausgesetzt, beide können wie Ehemann und Ehefrau nicht in einem my_company arbeiten. Ich habe ein Beispiel genommen

Also ist Employee ein referenziertes Modell, das von mehr als Dependent referenziert werden kann, das ein referenziertes Modell ist. Betrachten Sie nun den Beziehungsstatus wie folgt:

Employee:        Dependent:
+------+        +------+--------+-------------+--------------+
| name |        | name | E-name | school_mark | college_mark |
+------+        +------+--------+-------------+--------------+
| A    |        | a1   |   A    |          79 |           81 |
| B    |        | b1   |   B    |          80 |           60 |
+------+        | b2   |   B    |          68 |           86 |
                +------+--------+-------------+--------------+  

Abhängigera1 verweist auf MitarbeiterA und abhängigerb1, b2 verweist auf MitarbeiterB.

Jetzt ist meine Frage:

Finden Sie alle Mitarbeiter, deren Sohn/Tochter sowohl in der Schule als auch in der Schule Unterscheidungsmerkmale aufweist (z. B.> = 75%)?

>>> Employee.objects.filter(dependent__school_mark__gte=75,
...                         dependent__college_mark__gte=75)

[<Employee: A>]

Die Ausgabe ist 'A' abhängig. 'A1' hat Unterscheidungsmerkmale an der Hochschule und die Schule ist abhängig von Mitarbeiter 'A'. Hinweis 'B' ist nicht ausgewählt, da das Kind von 'B' sowohl in der Schule als auch in der Hochschule Unterscheidungsmerkmale aufweist. Relationale Algebra:

Mitarbeiter (school_mark> = 75 AND college_mark> = 75)Abhängig

Im zweiten Fall brauche ich eine Abfrage:

Finden Sie alle Mitarbeiter, deren Angehörige in Hochschule und Schule Unterscheidungsmerkmale aufweisen?

>>> Employee.objects.filter(
...             dependent__school_mark__gte=75
...                ).filter(
...             dependent__college_mark__gte=75)

[<Employee: A>, <Employee: B>]

Dieses Mal wurde "B" auch ausgewählt, weil "B" zwei Kinder hat (mehr als eines!), Eines in der Schule "b1" und das andere in der Hochschule "b2".
Die Reihenfolge der Filter spielt keine Rolle, wir können die obige Abfrage auch schreiben als:

>>> Employee.objects.filter(
...             dependent__college_mark__gte=75
...                ).filter(
...             dependent__school_mark__gte=75)

[<Employee: A>, <Employee: B>]

ergebnis ist das gleiche! Relationale Algebra kann sein:

(Mitarbeiter (Schulnote> = 75)Abhängig) (college_mark> = 75)Abhängig

Beachten Sie Folgendes:

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)

Gibt das gleiche Ergebnis aus: [<Dependent: a1>]

Ich überprüfe die von Django generierte Ziel-SQL-Abfrage mit print qd1.query und print qd2.query. Beide sind identisch (Django 1.6).

Aber semantisch unterscheiden sich beide von mir . sieht zunächst aus wie einfacher Abschnitt σ[school_mark> = 75 AND college_mark> = 75](Abhängig) und zweite wie langsam verschachtelte Abfrage: σ[school_mark> = 75][college_mark> = 75](Abhängig)).

Wenn man Code @codepad braucht

übrigens, es ist in der Dokumentation angegeben. @ Spanning multi-valued relationships Ich habe gerade ein Beispiel hinzugefügt, ich denke, es wird für jemanden hilfreich sein, der neu ist.

15
Grijesh Chauhan

Meistens gibt es nur eine mögliche Ergebnismenge für eine Abfrage.

Die Verkettung von Filtern erfolgt beim Umgang mit m2m:

Bedenken Sie:

# 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))

Andere Beispiele sind willkommen.

15

Der Leistungsunterschied ist enorm. Probieren Sie es aus und sehen Sie.

Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)

ist überraschend langsam im Vergleich zu

Model.objects.filter(condition_a, condition_b, condition_c)

Wie in "Effective Django ORM" erwähnt,

  • QuerySets behalten den Status im Speicher bei
  • Durch Verketten wird das Klonen ausgelöst und dieser Zustand dupliziert
  • Leider behält QuerySets viel Zustand bei
  • Wenn möglich, verketten Sie nicht mehr als einen Filter
9
tar

Sie können das Verbindungsmodul verwenden, um die zu vergleichenden unformatierten SQL-Abfragen anzuzeigen. Wie von Yuji erklärt, sind sie größtenteils gleichwertig, wie hier gezeigt:

>>> 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

Benötigt a und b dann

and_query_set = Model.objects.filter(a=a, b=b)

wenn a sowie b dann erfordert

chaied_query_set = Model.objects.filter(a=a).filter(b=b)

Offizielle Dokumente: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

Related Post: Verkettung mehrerer Filter () in Django, ist das ein Fehler?

0
Tony Jasur

Wenn Sie auf dieser Seite nach einem dynamischen Aufbau eines Django-Querysets mit mehreren Verkettungsfiltern suchen, die Filter jedoch vom Typ AND anstelle von OR sein sollen, sollten Sie Q objects verwenden.

Ein Beispiel:

# 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