¿Cómo hago un no igual en el filtrado de conjuntos de consultas de Django?

666

En el modelo de Django QuerySets, veo que hay un __gty __ltpara valores comparativos, pero ¿hay un __ne/ !=/ <>( no es igual ?)

Quiero filtrar usando un no igual:

Ejemplo:

Model:
    bool a;
    int x;

quiero

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

La !=sintaxis no es correcta. Probé __ne, <>.

Terminé usando:

results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)
MikeN
fuente
75
¿Los resultados = Model.objects.exclude (a = true) .filter (x = 5) habrían funcionado?
hughdbrown
3
@hughdbrown. No. Su consulta excluye todo a=trueprimero y luego aplica el x=5filtro al resto. La consulta prevista solo requería aquellos con a=truey x!=5. La diferencia es que todos aquellos con a=truey x=5también se filtran.
Mitchell van Zuylen

Respuestas:

690

Quizás los objetos Q podrían ser de ayuda para este problema. Nunca los he usado, pero parece que se pueden negar y combinar de manera muy similar a las expresiones normales de Python.

Actualización: acabo de probarlo, parece funcionar bastante bien:

>>> 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>, ...]
Dave Vogt
fuente
16
@ JCLeitão: vea también la respuesta de @ d4nt a continuación para una sintaxis más intuitiva.
Paul D. Waite
612

Su consulta parece tener un doble negativo, desea excluir todas las filas donde x no es 5, por lo tanto, en otras palabras, desea incluir todas las filas donde x ES 5. Creo que esto hará el truco.

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

Para responder a su pregunta específica, no existe un "no igual a", pero probablemente sea porque django tiene disponibles los métodos de "filtro" y "exclusión", por lo que siempre puede cambiar la ronda lógica para obtener el resultado deseado.

d4nt
fuente
2
@ d4nt: Puedo estar equivocado, pero creo que la consulta debería serresults = Model.objects.filter(a=true).exclude(x=5)
Taranjeet
1
@Taranjeet: Creo que leíste mal la consulta original. La versión de d4nt es correcta, porque OP quería excluir (a = Verdadero) y negar la exclusión de x = 5 (es decir, incluirla).
Chuck
3
Creo que esto está mal porque una instancia (x = 4, a = falso) se excluiría erróneamente.
RemcoGerlich
44
@danigosa Eso no parece correcto. Solo intenté esto yo mismo, y el orden excludey las filterllamadas no hicieron ninguna diferencia significativa. El orden de las condiciones en la WHEREcláusula cambia, pero ¿cómo importa eso?
coredumperror
44
El orden de exclusión y filtro de @danigosa no importa.
EralpB
132

La field=valuesintaxis en las consultas es una abreviatura de field__exact=value. Es decir que Django coloca operadores de consulta en campos de consulta en los identificadores . Django es compatible con los siguientes operadores:

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

Estoy seguro de que al combinarlos con los objetos Q como sugiere Dave Vogt y al usar filter()o exclude()como Jason Baker sugiere , obtendrá exactamente lo que necesita para cualquier consulta posible.

SingleNegationElimination
fuente
gracias esto es genial Usé algo como esto tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$')y funciona.
suhailvs
@suhail, tenga en cuenta que no todas las bases de datos admiten esa sintaxis de
expresiones
2
i in icontains, iexacty similar significa "ignorar mayúsculas y minúsculas". No es para "inversa".
Ivy Growing
Vale la pena señalar que cuando está utilizando exclude()varios términos, es posible que desee redactar la propuesta con el ORoperador, por ejemplo exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2)), para excluir los resultados en ambas condiciones.
clapas
98

Es fácil crear una búsqueda personalizada con Django 1.7. Hay un __neejemplo de búsqueda en la documentación oficial de Django .

Primero debe crear la búsqueda en sí:

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

Entonces necesitas registrarlo:

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

Y ahora puede usar la __nebúsqueda en sus consultas de esta manera:

results = Model.objects.exclude(a=True, x__ne=5)
Dmitrii Mikhailov
fuente
88

En Django 1.9 / 1.10 hay tres opciones.

  1. Cadena excludeyfilter

    results = Model.objects.exclude(a=true).filter(x=5)
  2. Usa Q()objetos y el ~operador

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
  3. Registrar una función de búsqueda personalizada

    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

    El register_lookupdecorador se agregó en Django 1.8 y permite la búsqueda personalizada como de costumbre:

    results = Model.objects.exclude(a=True, x__ne=5)
ilse2005
fuente
1
object_list = QuerySet.filter (~ Q (a = True), x = 5): Recuerde mantener todas las demás condiciones que no contengan Q después de las que contienen Q.
Bhumi Singhal
1
@MichaelHoffmann: A) luego filtrará un conjunto de datos más pequeño después de la exclusión usando ~ Q, por lo que es más eficiente. B) probablemente la secuencia al revés no funciona ... no sé ... ¡no recuerdo!
Bhumi Singhal
41

Mientras que con los modelos, puede filtrar con =, __gt, __gte, __lt, __lte, no se puede utilizar ne, !=o <>. Sin embargo, puede lograr un mejor filtrado al usar el objeto Q.

Usted puede evitar el encadenamiento QuerySet.filter()y QuerySet.exlude(), y usar esto:

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

Pendiente decisión de diseño. Mientras tanto, useexclude()

El rastreador de problemas de Django tiene la notable entrada # 5763 , titulada "Queryset no tiene un operador de filtro" no igual " . Es notable porque (a partir de abril de 2016) se "abrió hace 9 años" (en la edad de piedra de Django), "se cerró hace 4 años" y "se modificó por última vez hace 5 meses".

Lea la discusión, es interesante. Básicamente, algunas personas discuten__ne que se debe agregar mientras que otras dicen que exclude()es más claro y, por __ne lo tanto , no se debe agregar.

(Estoy de acuerdo con el anterior, ya que este último argumento es más o menos equivalente a decir Python no debe tener !=, ya que tiene ==y notque ya ...)

Lutz Prechelt
fuente
22

Usando excluir y filtrar

results = Model.objects.filter(x=5).exclude(a=true)
jincy mariam
fuente
18

Deberías usar filtery excludeasí

results = Model.objects.exclude(a=true).filter(x=5)
fuera de tiempo
fuente
8

El último bit de código excluirá todos los objetos donde x! = 5 y a es True. Prueba esto:

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

Recuerde, el signo = en la línea anterior está asignando False al parámetro a y el número 5 al parámetro x. No es verificar la igualdad. Por lo tanto, no hay realmente ninguna forma de usar el símbolo! = En una llamada de consulta.

Jason Baker
fuente
3
Eso no es 100% lo mismo, ya que también podría haber valores nulos para esos campos.
MikeN
Esto devuelve en sólo aquellos elementos que tienen un = false y x = 5, pero en la cuestión se incluiría una instancia (a = falso, x = 4).
RemcoGerlich
1
results = Model.objects.filter(a__in=[False,None],x=5)
Jeremy
8

resultados = Model.objects.filter (a = True) .exclude (x = 5)
Genera este sql:
seleccione * de tablex donde a! = 0 yx! = 5
El sql depende de cómo esté representado su campo Verdadero / Falso y del motor de la base de datos. Sin embargo, el código django es todo lo que necesitas.

M. Dasn
fuente
8

Django-model-values (revelación: autor) proporciona una implementación de la búsqueda NotEqual , como en esta respuesta . También proporciona soporte sintáctico para ello:

from model_values import F
Model.objects.exclude(F.x != 5, a=True)
A. coadyuvante
fuente
6

Lo que está buscando son todos los objetos que tienen a=false o x=5 . En Django, |sirve como ORoperador entre conjuntos de consultas:

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

¡Cuidado con muchas respuestas incorrectas a esta pregunta!

La lógica de Gerard es correcta, aunque devolverá una lista en lugar de un conjunto de consultas (lo que podría no importar).

Si necesita un conjunto de consultas, use Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
Mark Bailey
fuente