Filtern nach leeren oder NULL-Namen in einem Abfragesatz

463

Ich habe first_name, last_nameund alias(optional) , die ich für die Suche benötigen. Ich benötige also eine Abfrage, um alle Namen zu erhalten, für die ein Alias ​​festgelegt ist.

Nur wenn ich könnte:

Name.objects.filter(alias!="")

Was ist das Äquivalent zu dem oben genannten?

un33k
quelle

Antworten:

839

Sie könnten dies tun:

Name.objects.exclude(alias__isnull=True)

Wenn Sie Nullwerte und leere Zeichenfolgen ausschließen müssen, können Sie die Bedingungen wie folgt miteinander verketten:

Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')

Wenn Sie diese Methoden miteinander verketten, wird grundsätzlich jede Bedingung unabhängig überprüft: Im obigen Beispiel schließen wir Zeilen aus, in denen aliasentweder null oder eine leere Zeichenfolge ist, sodass Sie alle NameObjekte erhalten, die ein nicht null, nicht leeres aliasFeld haben. Das generierte SQL würde ungefähr so ​​aussehen:

SELECT * FROM Name WHERE alias IS NOT NULL AND alias != ""

Sie können auch mehrere Argumente an einen einzelnen Aufruf von übergeben exclude, um sicherzustellen, dass nur Objekte ausgeschlossen werden, die alle Bedingungen erfüllen :

Name.objects.exclude(some_field=True, other_field=True)

Hier werden Zeilen, in denen some_field und other_field wahr sind, ausgeschlossen, sodass wir alle Zeilen erhalten, in denen beide Felder nicht wahr sind. Der generierte SQL-Code würde ungefähr so ​​aussehen:

SELECT * FROM Name WHERE NOT (some_field = TRUE AND other_field = TRUE)

Wenn Ihre Logik komplexer ist, können Sie alternativ Djangos Q-Objekte verwenden :

from django.db.models import Q
Name.objects.exclude(Q(alias__isnull=True) | Q(alias__exact=''))

Weitere Informationen finden Sie auf dieser Seite und auf dieser Seite in den Django-Dokumenten.

Nebenbei: Meine SQL-Beispiele sind nur eine Analogie - der tatsächlich generierte SQL-Code wird wahrscheinlich anders aussehen. Sie erhalten ein tieferes Verständnis der Funktionsweise von Django-Abfragen, indem Sie sich das von ihnen generierte SQL ansehen.

Sasha Chedygov
quelle
5
Ich glaube, dass Ihre Bearbeitung falsch ist: Der Verkettungsfilter erstellt NICHT automatisch eine SQL OR(nur in diesem Fall), sondern eine SQL AND. Weitere Informationen finden Sie auf dieser Seite: docs.djangoproject.com/de/dev/topics/db/queries/… Der Vorteil der Verkettung besteht darin, dass Sie komplizierte Abfragebedingungen mischen excludeund filtermodellieren können. Wenn Sie eine echte SQL modellieren möchten, ORmüssen Sie ein Django Q-Objekt verwenden: docs.djangoproject.com/de/dev/topics/db/queries/… Bitte bearbeiten Sie Ihre Bearbeitung, um dies widerzuspiegeln, da die Antwort derzeit stark irreführend ist .
Shezi
1
@shezi: Ich meinte es eher als Analogie - ich meinte nicht, dass der tatsächliche SQL-Code garantiert ein verwendet OR, um die Bedingungen zu verschmelzen. Ich werde meine Antwort bearbeiten, um dies zu klären.
Sasha Chedygov
1
Denken Sie daran, dass es verschiedene Möglichkeiten gibt, diese Logik darzustellen - zum Beispiel NOT (A AND B)gleichbedeutend mit NOT A OR NOT B. Ich denke, das macht die Dinge für neue Django-Entwickler verwirrend, die SQL kennen, aber mit ORMs nicht vertraut sind.
Sasha Chedygov
3
Ich kenne das Gesetz von De Morgan, und das ist genau mein Punkt: Ihr Beispiel funktioniert nur, weil es von Vorteil ist, das ANDin der ersten Abfrage in ein zu verwandeln, ORweil Sie es verwenden exclude. Im allgemeinen Fall ist es wahrscheinlich richtiger, sich Verkettung als a vorzustellen THEN, dh exclude(A) THEN exclude(B). Entschuldigung für die raue Sprache oben. Ihre Antwort ist wirklich gut, aber ich mache mir Sorgen, dass neue Entwickler Ihre Antwort zu allgemein nehmen.
Shezi
2
@ Shezi: Fair genug. Ich bin damit einverstanden , dass es besser ist , daran zu denken in Django Bedingungen und nicht in SQL ausgedrückt, ich dachte nur , dass in Bezug auf die Verkettungs präsentiert ANDund ORkönnte für jemanden nützlich sein Kommen zu Django aus einem SQL - Hintergrund. Für ein tieferes Verständnis von Django denke ich, dass die Dokumente einen besseren Job machen als ich kann.
Sasha Chedygov
49
Name.objects.filter(alias__gt='',alias__isnull=False)
jbofill
quelle
2
Ich bin nicht sicher, aber ich denke, die alias__isnull=FalseBedingung ist überflüssig. Wenn das Feld Nullsicher ist, wird es durch die erste Klausel ausgeschlossen?
Bobble
Abgesehen von meinem früheren Kommentar / meiner früheren Frage denke ich, dass die positive Logik hier leichter zu befolgen ist als in einigen anderen Antworten.
Bobble
@ Bobble, die von der Datenbankimplementierung abhängen würde - Reihenfolge wird
wpercy
alias__gtwar das einzige, was für JSON-Spalten funktionierte, bei denen ich leere Zeichenfolgen wie JSON ausschließen wollte {'something:''}. Die funktionierende Syntax lautet also:jsoncolumnname__something__gt=''
Bartgras
38

Erstens wird in den Django-Dokumenten dringend empfohlen, keine NULL-Werte für stringbasierte Felder wie CharField oder TextField zu verwenden. Lesen Sie die Dokumentation zur Erklärung:

https://docs.djangoproject.com/de/dev/ref/models/fields/#null

Lösung: Ich denke, Sie können Methoden in QuerySets auch miteinander verketten. Versuche dies:

Name.objects.exclude(alias__isnull=True).exclude(alias="")

Das sollte dir das Set geben, das du suchst.

b3ng0
quelle
5

Von Django 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)
Chemischer Programmierer
quelle
5
Dies scheint ein „etwas , das Sie können tun“, nicht etwas , das Sie sollten tun. Die Komplexität der Abfragen wird durch zwei einfache Überprüfungen erheblich gesteigert.
Oli
3

Denken Sie daran, um häufige Fehler bei der Verwendung zu vermeiden exclude:

Sie können einem exclude () -Block wie nicht mehrere Bedingungen hinzufügen . Um mehrere Bedingungen auszuschließen, müssen Sie mehrere exclude () verwenden.filter

Beispiel

Falsch :

User.objects.filter (email='[email protected] '). Exclude (profile__nick_name =' ', profile__avt =' ')

Richtig :

User.objects.filter (email='[email protected] '). Exclude (profile__nick_name =' '). Exclude (profile__avt =' ')

HoangYell
quelle
0

Sie können dies einfach tun:

Name.objects.exclude(alias="").exclude(alias=None)

Es ist wirklich so einfach. filterwird verwendet, um übereinzustimmen und excludeum alles zusammenzubringen, außer was es spezifiziert. Dies würde in SQL als ausgewertet NOT alias='' AND alias IS NOT NULL.

Tim Tisdall
quelle
Das ist falsch. Die Frage zielt darauf ab, leere ( alias="") und NULL ( alias=None) Aliase von der Abfrage auszuschließen . Ihre würde Instanzen mit einschließen Name(alias=None).
Damon
@damon - Ich habe geantwortet, was .filter(alias!="")dem Titel entspricht, aber nicht. Ich habe meine Antwort bearbeitet. Zeichenfelder sollten jedoch keine NULL-Werte zulassen und die leere Zeichenfolge für einen Nichtwert verwenden (gemäß Konvention).
Tim Tisdall
-1

Dies ist ein weiterer einfacher Weg, dies zu tun.

Name.objects.exclude(alias=None)
ImadOS
quelle
Noneist nicht dasselbe wie "".
Tim Tisdall