Filtrowanie pustych lub NULL nazw w zestawie zapytań


463

Mam first_name, last_namei alias(opcjonalnie), które muszę szukać. Potrzebuję więc zapytania, aby podać wszystkie nazwy, które mają ustawiony alias.

Tylko gdybym mógł:

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

Więc co jest równoważne z powyższym?

Odpowiedzi:


839

Możesz to zrobić:

Name.objects.exclude(alias__isnull=True)

Jeśli chcesz wykluczyć wartości puste i puste ciągi, preferowanym sposobem jest połączenie ze sobą następujących warunków:

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

Łączenie tych metod razem zasadniczo sprawdza każdy warunek niezależnie: w powyższym przykładzie wykluczamy wiersze, w których aliasjest albo zerowy, albo pusty ciąg znaków, więc otrzymujesz wszystkie Nameobiekty, które mają niepuste, niepuste aliaspole. Wygenerowany SQL wyglądałby mniej więcej tak:

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

Możesz również przekazać wiele argumentów do pojedynczego wywołania exclude, co zapewni, że wykluczone zostaną tylko obiekty spełniające każdy warunek:

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

Tutaj wiersze, w których some_field i other_field są prawdziwe, są wykluczane, więc otrzymujemy wszystkie wiersze, w których oba pola nie są prawdziwe. Wygenerowany kod SQL wyglądałby trochę tak:

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

Alternatywnie, jeśli twoja logika jest bardziej złożona, możesz użyć obiektów Q Django :

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

Aby uzyskać więcej informacji, zobacz tę stronę i tę stronę w dokumentach Django.

Nawiasem mówiąc: moje przykłady SQL są tylko analogią - faktyczny wygenerowany kod SQL prawdopodobnie będzie wyglądał inaczej. Zgłębisz zrozumienie działania zapytań Django, patrząc na generowany przez nich SQL.


5
Uważam, że twoja edycja jest niepoprawna: Filtr łańcuchowy NIE tworzy automatycznie SQL OR(tylko w tym przypadku), tworzy SQL AND. Zobacz tę stronę w celach informacyjnych: docs.djangoproject.com/en/dev/topics/db/queries/… Zaletą tworzenia łańcuchów jest mieszanie excludei filtermodelowanie skomplikowanych warunków zapytań. Jeśli chcesz wymodelować prawdziwy SQL OR, musisz użyć obiektu Django Q: docs.djangoproject.com/en/dev/topics/db/queries/... Edytuj swoją edycję, aby to odzwierciedlić, ponieważ odpowiedź jest bardzo myląca .
shezi

1
@shezi: Miałem na myśli to bardziej jako analogię - nie miałem na myśli, że rzeczywisty kod SQL ma gwarancję, że użyje on ORdo połączenia warunków. Zmodyfikuję swoją odpowiedź, aby wyjaśnić.
Sasha Chedygov

1
Należy pamiętać, że istnieją różne sposoby reprezentowania tej logiki - na przykład NOT (A AND B)jest równoważne NOT A OR NOT B. Myślę, że to wprowadza zamieszanie u nowych programistów Django, którzy znają SQL, ale nie znają ORM.
Sasha Chedygov

3
Znam prawo De Morgana i właśnie o to mi chodzi: Twój przykład działa tylko dlatego, że korzysta z przekształcenia ANDpierwszego zapytania w ORponieważ używasz exclude. W ogólnym przypadku prawdopodobnie bardziej poprawne jest myślenie o łańcuchach jako THEN, tj exclude(A) THEN exclude(B). Przepraszamy za ostry język powyżej. Twoja odpowiedź jest naprawdę dobra, ale martwię się, że nowi programiści przyjmą ją zbyt ogólnie.
shezi

2
@shezi: Wystarczająco sprawiedliwe. Zgadzam się, że lepiej myśleć o tym w kategoriach Django, a nie w języku SQL, po prostu pomyślałem, że prezentowanie łańcuchów pod względem ANDi ORmoże być przydatne dla kogoś, kto przyjeżdża do Django z tła SQL. Aby lepiej zrozumieć Django, myślę, że doktorzy wykonują lepszą robotę niż potrafię.
Sasha Chedygov

49
Name.objects.filter(alias__gt='',alias__isnull=False)

2
Nie jestem pewien, ale myślę, że alias__isnull=Falsewarunek jest zbędny. Jeśli pole jest z Nullpewnością, zostanie wykluczone przez pierwszą klauzulę?
Bobble

Poza moim wcześniejszym komentarzem / pytaniem myślę, że tutaj można podążać za pozytywną logiką niż w niektórych innych odpowiedziach.
Bobble

@ Bobble, który zależałby od implementacji bazy danych - kolejność jest przekazywana do
wpercy

alias__gtbyła jedyną rzeczą, która działała w kolumnach typu JSON, w których chciałem wykluczyć puste ciągi znaków z JSON jak {'something:''}. Więc działająca składnia to:jsoncolumnname__something__gt=''
bartgras

38

Po pierwsze, dokumenty Django zdecydowanie nie zalecają używania wartości NULL dla pól opartych na ciągach znaków, takich jak CharField lub TextField. Przeczytaj dokumentację wyjaśniającą:

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

Rozwiązanie: Myślę, że możesz również łączyć ze sobą metody w QuerySets. Spróbuj tego:

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

To powinno dać ci zestaw, którego szukasz.


5

Od Django 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)

5
To wydaje się być „czymś, co możesz zrobić”, a nie czymś, co powinieneś zrobić. Znacząco rozkwita złożoność zapytania w porównaniu do dwóch prostych kontroli.
Oli

3

Aby uniknąć typowych błędów podczas używania exclude, pamiętaj:

Można nie dodać wiele warunków do wykluczenia () bloku podobnego filter. Aby wykluczyć wiele warunków, musisz użyć wielu wykluczeń ()

Przykład

Błędny :

User.objects.filter (email='example@example.com '). Exclude (profile__nick_name =' ', profile__avt =' ')

Poprawny :

User.objects.filter (email='example@example.com '). Exclude (profile__nick_name =' '). Exclude (profile__avt =' ')


0

Możesz po prostu to zrobić:

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

To naprawdę takie proste. filtersłuży do dopasowania i excludema na celu dopasowanie wszystkiego oprócz tego, co określa. Oznaczałoby to wyrażenie SQL jako NOT alias='' AND alias IS NOT NULL.


To jest niepoprawne. Pytanie ma na celu wykluczenie z zapytania aliasów pustych ( alias="") i NULL ( alias=None). Twoje obejmowałyby wystąpienia z Name(alias=None).
damon

@damon - odpowiadałem na pytanie, co odpowiadało .filter(alias!="")tytułowi, ale nie było. Zredagowałem swoją odpowiedź. Jednak pola znakowe nie powinny zezwalać na wartości NULL i używać pustego ciągu jako wartości innej niż (zgodnie z konwencją).
Tim Tisdall,

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.