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

Elisa
fuente

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

Lakshman Prasad
fuente
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 .

placas
fuente
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


jojo
fuente