Filtro per nomi vuoti o NULL in un set di query


463

Ho first_name, last_namee alias(optional), che ho bisogno di cercare. Quindi, ho bisogno di una query per darmi tutti i nomi che hanno un alias impostato.

Solo se potessi fare:

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

Quindi, qual è l'equivalente di quanto sopra?

Risposte:


841

Potresti farlo:

Name.objects.exclude(alias__isnull=True)

Se è necessario escludere valori nulli e stringhe vuote, il modo preferito per farlo è di concatenare le condizioni in questo modo:

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

Il concatenamento di questi metodi fondamentalmente controlla ogni condizione in modo indipendente: nell'esempio sopra, escludiamo le righe dove aliasè nullo o una stringa vuota, in modo da ottenere tutti gli Nameoggetti che hanno un campo non nullo, non vuoto alias. L'SQL generato sarebbe simile a:

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

Puoi anche passare più argomenti a una singola chiamata exclude, in modo da escludere solo gli oggetti che soddisfano tutte le condizioni:

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

Qui, le righe in cui some_field e other_field true sono escluse, quindi otteniamo tutte le righe in cui entrambi i campi non sono true. Il codice SQL generato sarebbe simile al seguente:

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

In alternativa, se la tua logica è più complessa di quella, potresti usare gli oggetti Q di Django :

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

Per maggiori informazioni consulta questa pagina e questa pagina nei documenti Django.

A parte questo: i miei esempi SQL sono solo un'analogia: il codice SQL generato reale probabilmente avrà un aspetto diverso. Otterrai una comprensione più approfondita del funzionamento delle query Django osservando effettivamente l'SQL che generano.


5
Credo che la tua modifica sia sbagliata: il filtro concatenato NON crea automaticamente un SQL OR(solo in questo caso), produce un SQL AND. Vedere questa pagina per riferimento: docs.djangoproject.com/en/dev/topics/db/queries/… Il vantaggio del concatenamento è che è possibile combinare excludee filtermodellare condizioni di query complesse. Se si desidera modellare un SQL reale, ORè necessario utilizzare un oggetto Django Q: docs.djangoproject.com/en/dev/topics/db/queries/… Modifica la modifica per riflettere ciò, poiché la risposta è gravemente fuorviante così com'è .
Shezi,

1
@shezi: lo intendevo più come un'analogia - non intendevo dire che il codice SQL effettivo garantisse l'uso di un ORper fondere le condizioni. Modificherò la mia risposta per chiarire.
Sasha Chedygov,

1
Tieni presente che ci sono diversi modi per rappresentare questa logica - ad esempio, NOT (A AND B)è equivalente a NOT A OR NOT B. Penso che ciò crei confusione per i nuovi sviluppatori Django che conoscono SQL ma non hanno familiarità con gli ORM.
Sasha Chedygov,

3
Conosco la legge di De Morgan, e questo è esattamente il mio punto: il tuo esempio funziona solo perché sfrutta la trasformazione ANDdella prima query in una ORperché stai usando exclude. Nel caso generale, è probabilmente più corretto pensare di concatenare un THEN, cioè exclude(A) THEN exclude(B). Mi dispiace per il linguaggio aspro sopra. La tua risposta è davvero buona, ma sono preoccupato per i nuovi sviluppatori che prendono la tua risposta troppo in generale.
Shezi,

2
@shezi: abbastanza giusto. Sono d'accordo che è meglio pensarci in termini di Django e non in termini di SQL, ho solo pensato che presentare il concatenamento in termini di ANDe ORpotrebbe essere utile per qualcuno che viene a Django da uno sfondo SQL. Per una comprensione più approfondita di Django, penso che i documenti facciano un lavoro migliore di quello che posso.
Sasha Chedygov,

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

2
Non ne sono sicuro, ma penso che la alias__isnull=Falsecondizione sia ridondante. Se il campo è Nullsicuramente verrà escluso dalla prima clausola?
Bobble,

A parte il mio precedente commento / domanda, penso che la logica positiva qui sia più facile da seguire che in alcune delle altre risposte.
Bobble,

@Bobble che dipenderebbe dall'implementazione del database - l' ordinamento è delegato al databse
wpercy

alias__gtè stata l'unica cosa che ha funzionato per le colonne di tipo JSON in cui volevo escludere stringhe vuote da JSON come {'something:''}. Quindi la sintassi di lavoro è:jsoncolumnname__something__gt=''
bartgras il

38

In primo luogo, i documenti Django consigliano vivamente di non utilizzare i valori NULL per i campi basati su stringhe come CharField o TextField. Leggi la documentazione per la spiegazione:

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

Soluzione: penso anche che sia possibile concatenare i metodi sui QuerySet. Prova questo:

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

Questo dovrebbe darti il ​​set che stai cercando.


5

Da Django 1.8,

from django.db.models.functions import Length

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

5
Sembra un "qualcosa che puoi fare", non qualcosa che dovresti fare. Fiorisce in modo significativo la complessità della query su due semplici controlli.
Oli,

3

Per evitare errori comuni durante l'utilizzo exclude, ricordare:

È possibile non aggiungere più condizioni in una escludere () blocco come filter. Per escludere più condizioni, è necessario utilizzare più exclude ()

Esempio

Errato :

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

Corretto :

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


0

Puoi semplicemente farlo:

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

È davvero così semplice. filterè usato per abbinare ed excludeè per abbinare tutto tranne ciò che specifica. Ciò valuterebbe in SQL come NOT alias='' AND alias IS NOT NULL.


Questo non è corretto La domanda ha lo scopo di escludere gli alias vuoti ( alias="") e NULL ( alias=None) dalla query. I tuoi includono esempi con Name(alias=None).
damon,

@damon - Stavo rispondendo a ciò che era equivalente .filter(alias!="")ma non al titolo. Ho modificato la mia risposta. Tuttavia, i campi di caratteri non dovrebbero consentire valori NULL e utilizzare la stringa vuota per un non valore (come da convenzione).
Tim Tisdall,

-1

questo è un altro modo semplice per farlo.

Name.objects.exclude(alias=None)

Nonenon è la stessa cosa di "".
Tim Tisdall,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.