¿Cómo realizar la condición OR en el django queryset?


294

Quiero escribir una consulta Django equivalente a esta consulta SQL:

SELECT * from user where income >= 5000 or income is NULL.

¿Cómo construir el filtro de conjunto de consultas Django?

User.objects.filter(income__gte=5000, income=0)

Esto no funciona, porque son ANDlos filtros. Quiero que ORlos filtros obtengan la unión de conjuntos de consultas individuales.


Respuestas:


548
from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

a través de la documentación


Sería útil si agrega una impresión de object.query para que podamos relacionar los resultados de ORM y de Consulta para familiarizarnos con él. Por cierto gran ejemplo.
— Eddwin Paz

¿Es mejor usar este tipo de consulta o realizar dos consultas separadas?
— MHB

60

Debido a que QuerySets implementa el __or__operador Python ( |), o unión, simplemente funciona. Como era de esperar, el |operador binario devuelve una QuerySetmanera order_by(), .distinct()y otros filtros de QuerySet se puede unir hasta el final.

combined_queryset = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)
ordered_queryset = combined_queryset.order_by('-income')

Actualización 2019-06-20: Esto ahora está completamente documentado en la referencia de la API de QuejanSet de Django 2.1 . Se puede encontrar más discusión histórica en el boleto de DjangoProject # 21333 .


18
"indocumentado" y "legado" me dan miedo. Creo que es más seguro usar el objeto Q, como se detalla en la respuesta aceptada aquí.
— 0atman

2
Para su información, order_by () y distinct () se pueden aplicar al conjunto de consultas canalizadas después de que se combinen
— carruthd

@carruthd gracias. Confirmé esto también. Se editará
— hobs

¿Se puede aplicar order_by () a cada conjunto de consultas individual y luego combinarlo? ¿Para que se mantenga el orden de cada condición? Por ejemplo, combine_queryset = User.objects.filter (renta__gte = 5000) .order_by ('renta') | Usuario.objetos.filtro (ingresos__lt = 5000) .order_by ('- ingresos')?
— punto muerto el

2
@Oatman: | El operador está documentado. Consulte docs.djangoproject.com/en/2.0/ref/models/querysets : "En general, los objetos Q () permiten definir y reutilizar condiciones. Esto permite la construcción de consultas complejas de bases de datos utilizando | (OR) y & ( AND) operadores; en particular, no es posible utilizar OR en QuerySets ". No verifiqué la documentación de versiones anteriores, pero el operador de tubería funciona desde Django 1.1.4 al menos (solo lo intenté).
— makeroo

10

Ambas opciones ya se mencionan en las respuestas existentes:

from django.db.models import Q
q1 = User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True))

y

q2 = User.objects.filter(income__gte=5000) | User.objects.filter(income__isnull=True)

Sin embargo, parece haber cierta confusión con respecto a cuál preferir.

El punto es que son idénticos en el nivel SQL , ¡así que siéntete libre de elegir lo que quieras!

El libro de cocina de Django ORM habla en detalle sobre esto, aquí está la parte relevante:


queryset = User.objects.filter(
        first_name__startswith='R'
    ) | User.objects.filter(
    last_name__startswith='D'
)

lleva a

In [5]: str(queryset.query)
Out[5]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
"auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

y

qs = User.objects.filter(Q(first_name__startswith='R') | Q(last_name__startswith='D'))

lleva a

In [9]: str(qs.query)
Out[9]: 'SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
 "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
  "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff",
  "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"
  WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)'

fuente: django-orm-cookbook


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.