Come faccio a non eguagliare il filtro queryset Django?


666

Nel modello QuerySet di Django, vedo che c'è un __gte __ltper valori comparativi, ma c'è un __ne/ !=/ <>( non è uguale ?)

Voglio filtrare usando un non uguale:

Esempio:

Model:
    bool a;
    int x;

Voglio

results = Model.objects.exclude(a=true, x!=5)

La !=sintassi non è corretta. Ho provato __ne, <>.

Ho finito per usare:

results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)

75
Results = Model.objects.exclude (a = true) .filter (x = 5) avrebbe funzionato?
hughdbrown,

3
@hughdbrown. No. La tua query esclude a=trueprima tutto e quindi applica il x=5filtro sul resto. La query desiderata richiedeva solo quelli con a=truee x!=5. La differenza è che tutti quelli con a=truee x=5sono anche filtrati.
Mitchell van Zuylen,

Risposte:


690

Forse gli oggetti Q potrebbero essere di aiuto per questo problema. Non li ho mai usati ma sembra che possano essere negati e combinati in modo molto simile alle normali espressioni di pitone.

Aggiornamento: l'ho appena provato, sembra funzionare abbastanza bene:

>>> from myapp.models import Entry
>>> from django.db.models import Q

>>> Entry.objects.filter(~Q(id = 3))

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]

16
@ JCLeitão: vedi anche la risposta di @ d4nt in basso per una sintassi più intuitiva.
Paul D. Waite,

612

La tua query sembra avere un doppio negativo, vuoi escludere tutte le righe in cui x non è 5, quindi in altre parole vuoi includere tutte le righe in cui x È 5. Credo che questo farà il trucco.

results = Model.objects.filter(x=5).exclude(a=true)

Per rispondere alla tua domanda specifica, non esiste "non uguale a", ma probabilmente perché django ha entrambi i metodi "filtro" ed "esclusione" disponibili in modo da poter sempre cambiare la logica per ottenere il risultato desiderato.


2
@ d4nt: potrei sbagliarmi, ma penso che la domanda dovrebbe essereresults = Model.objects.filter(a=true).exclude(x=5)
Taranjeet,

1
@Taranjeet: Penso che tu abbia letto male la domanda originale. La versione di d4nt è corretta, perché OP ha voluto escludere (a = True) e negare l'esclusione di x = 5 (ovvero includerlo).
Chuck,

3
Penso che sia sbagliato perché un'istanza (x = 4, a = false) verrebbe erroneamente esclusa.
RemcoGerlich,

4
@danigosa Non sembra giusto. Ho appena provato questo, e l'ordine excludee le filterchiamate non hanno fatto alcuna differenza significativa. L'ordine delle condizioni nella WHEREclausola cambia, ma che importanza ha?
coredumperror,

4
L'ordine di esclusione e filtro di @danigosa non ha importanza.
EralpB,

132

la field=valuesintassi nelle query è una scorciatoia per field__exact=value. Ciò significa che Django colloca gli operatori di query sui campi di query negli identificatori . Django supporta i seguenti operatori:

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range
year
month
day
week_day
isnull
search
regex
iregex

Sono sicuro combinandoli con gli oggetti Q come suggerisce Dave Vogt e usando filter()o exclude()come suggerisce Jason Baker otterrai esattamente quello che ti serve per qualsiasi possibile query.


grazie è fantastico. ho usato qualcosa del genere tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$')e funziona.
suhailvs,

@suhail, tieni presente che non tutti i database supportano questa sintassi regex :)
Anoyz,

2
i in icontains, iexacte stand simili per "ignora maiuscole e minuscole". Non è per "inverso".
Ivy Growing,

Vale la pena notare che quando si utilizzano exclude()più termini, è possibile che si desideri comporre la proposta con l' ORoperatore, ad esempio exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2))per escludere i risultati in entrambe le condizioni.
Clapas,

98

È facile creare una ricerca personalizzata con Django 1.7. C'è un __neesempio di ricerca nella documentazione ufficiale di Django .

Devi prima creare la ricerca stessa:

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

Quindi è necessario registrarlo:

from django.db.models.fields import Field
Field.register_lookup(NotEqual)

E ora puoi utilizzare la __nericerca nelle tue query in questo modo:

results = Model.objects.exclude(a=True, x__ne=5)

88

In Django 1.9 / 1.10 ci sono tre opzioni.

  1. Catena excludeefilter

    results = Model.objects.exclude(a=true).filter(x=5)
  2. Usa gli Q()oggetti e l' ~operatore

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
  3. Registra una funzione di ricerca personalizzata

    from django.db.models import Lookup
    from django.db.models.fields import Field
    
    @Field.register_lookup
    class NotEqual(Lookup):
        lookup_name = 'ne'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params

    Il register_lookupdecoratore è stato aggiunto in Django 1.8 e consente la ricerca personalizzata come al solito:

    results = Model.objects.exclude(a=True, x__ne=5)

1
object_list = QuerySet.filter (~ Q (a = True), x = 5): Ricorda di mantenere tutte le altre condizioni che non contengono Q dopo quelle che contengono Q.
Bhumi Singhal

1
@MichaelHoffmann: A) filtrerai quindi su un set di dati più piccolo dopo l'esclusione usando ~ Q, quindi è più efficiente. B) probabilmente il sequenziamento al contrario non funziona .. dun lo so .. dun ricorda!
Bhumi Singhal,

41

Mentre con i modelli, è possibile filtrare con =, __gt, __gte, __lt, __lte, non è possibile utilizzare ne, !=o <>. Tuttavia, è possibile ottenere un filtro migliore utilizzando l'oggetto Q.

Puoi evitare il concatenamento QuerySet.filter()e QuerySet.exlude(), e usare questo:

from django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')

24

In attesa di decisione di progettazione. Nel frattempo, usaexclude()

Il tracker di problemi di Django ha la notevole voce # 5763 , intitolata "Queryset non ha un operatore di filtro" non uguale " . È notevole perché (ad aprile 2016) è stato "aperto 9 anni fa" (nell'età della pietra di Django), "chiuso 4 anni fa" e "modificato l'ultima volta 5 mesi fa".

Leggi la discussione, è interessante. Fondamentalmente, alcune persone sostengono che __nedovrebbe essere aggiunto, mentre altri dicono che exclude()è più chiaro e quindi non__ne dovrebbe essere aggiunto.

(Concordo con il primo, perché il secondo argomento è approssimativamente equivalente a dire che Python non dovrebbe avere !=perché ha ==e notgià ...)


22

Utilizzando exclude e filter

results = Model.objects.filter(x=5).exclude(a=true)

18

Dovresti usare filtere excludecosì

results = Model.objects.exclude(a=true).filter(x=5)

8

L'ultimo bit di codice esclude tutti gli oggetti in cui x! = 5 e a è True. Prova questo:

results = Model.objects.filter(a=False, x=5)

Ricorda, il segno = nella riga sopra sta assegnando False al parametro a e il numero 5 al parametro x. Non sta verificando l'uguaglianza. Pertanto, non esiste alcun modo per utilizzare il simbolo! = In una chiamata di query.


3
Non è la stessa cosa al 100% poiché potrebbero esserci anche valori Null per quei campi.
MikeN,

Ciò restituisce solo quegli elementi che hanno a = False e x = 5, ma nella domanda sarebbe inclusa un'istanza (a = false, x = 4).
RemcoGerlich,

1
results = Model.objects.filter(a__in=[False,None],x=5)
Jeremy

8

results = Model.objects.filter (a = True) .exclude (x = 5)
Genera questo sql:
seleziona * da tablex dove a! = 0 e x! = 5
Sql dipende da come è rappresentato il campo Vero / Falso e dal motore di database. Il codice Django è tutto ciò di cui hai bisogno.



6

Quello che stai cercando sono tutti gli oggetti che hanno a=false o x=5 . In Django, |funge da ORoperatore tra le query:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)

5

Questo darà il risultato desiderato.

from django.db.models import Q
results = Model.objects.exclude(Q(a=True) & ~Q(x=5))

per non uguale è possibile utilizzare ~su una query uguale. ovviamente, Qpuò essere usato per raggiungere la query uguale.


Si prega di controllare la modifica; l'uso di "e" in Q(a=True) and ~Q(x=5)valuterà ~Q(x=5)come argomenti a .exclude. Si prega di leggere: docs.python.org/3/reference/expressions.html#boolean-operations e docs.python.org/3/reference/… .
Tzot

2

Fai attenzione a molte risposte errate a questa domanda!

La logica di Gerard è corretta, anche se restituirà un elenco piuttosto che un queryset (che potrebbe non avere importanza).

Se hai bisogno di un queryset, usa Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
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.