update queries python django django-models django-queryset

python - queries - ¿Cómo hago una no igual en el filtrado de Django queryset?



orm django queries (13)

Decisión de diseño pendiente. Mientras tanto, use exclude()

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".

Leer a través de la discusión, es interesante. Básicamente, algunas personas argumentan que se debe agregar __ne , mientras que otros dicen que exclude() es más claro y, por __ne tanto, no se debe agregar __ne .

(Estoy de acuerdo con el primero, porque el último argumento es aproximadamente equivalente a decir que Python no debería tener != Porque tiene == y aún not ...)

En el modelo Django QuerySets, veo que hay un __gt y un __lt para los valores comparativos, pero hay un __ne / != / <> (¿ No es igual a ?)

Quiero filtrar utilizando un no es igual a:

Ejemplo:

Model: bool a; int x;

quiero

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

La != No es la sintaxis correcta. Intenté __ne , <> .

Terminé usando:

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


Debes usar el filter y exclude así

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


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

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

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


En Django 1.9 / 1.10 hay tres opciones.

  1. Cadena exclude y filter

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

  2. Usa los objetos Q() 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 decorador register_lookup se agregó en Django 1.8 y permite la búsqueda personalizada como de costumbre:

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


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

Necesitas crear primero la búsqueda:

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 búsqueda __ne en sus consultas de esta manera:

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


Lo que está buscando son todos los objetos que tienen ya sea a=false o x=5 . En Django, | Sirve como operador OR entre consultas:

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


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

Puede evitar el encadenamiento de QuerySet.filter() y QuerySet.exlude() , y usar esto:

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


Su consulta parece tener un doble negativo, quiere excluir todas las filas donde x no es 5, en otras palabras, quiere 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 hay "no igual a" pero eso es probablemente porque django tiene disponibles los métodos "filtro" y "excluir", por lo que siempre puede cambiar la lógica para obtener el resultado deseado.


Tal vez los objetos Q podrían ser de ayuda para este problema. Nunca los he usado, pero parece que se pueden negar y combinar de forma muy similar a las expresiones de python normales.

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>, ...]


Usando excluir y filtrar

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


la sintaxis de field=value en las consultas es una abreviatura de field__exact=value . Es decir, Django coloca los operadores de consulta en los campos de consulta en los identificadores . Django soporta 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 combinando estos con los objetos Q como sugiere Dave Vogt y utilizando filter() o exclude() como Jason Baker sugiere que obtendrá exactamente lo que necesita para cualquier consulta posible.


Django-model-values (divulgació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)


results = Model.objects.filter(a = True).exclude(x = 5) Generetes este sql:

select * from tablex where a != 0 and x !=5 El SQL depende de cómo se representa su campo Verdadero / Falso y el motor de la base de datos. El código django es todo lo que necesitas.