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

5 minutos de lectura

avatar de usuario
Elisa

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 de Django?

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

Esto no funciona, porque ANDs los filtros. Yo quiero OR los filtros para obtener la unión de conjuntos de consultas individuales.

  • Posible duplicado de ¿Cómo hago un filtro OR en una consulta de Django?

    – Underoos

    4 de julio de 2019 a las 13:08

avatar de usuario
lprsd

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 la salida ORM y Query para familiarizarnos con ella. Por cierto gran ejemplo.

    – Edwin Paz

    23 de agosto de 2017 a las 21:05

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

    – MHB

    16 de marzo de 2020 a las 15:06

  • ¿Qué pasa si hay otras consultas también junto con este @lakshman?

    – Faiz Hameed

    17 de julio de 2020 a las 4:52


  • si ambas consultas son iguales, devolverá consultas duplicadas. ¿Cómo evitar eso?

    – Osman Hamashool

    5 de noviembre de 2021 a las 12:57

  • Acabo de encontrar cómo evitar la duplicación, después de 6 min. Antes de la consulta, utilice la función set(). me gusta: set(User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True)))

    – Osman Hamashool

    5 de noviembre de 2021 a las 13:08

avatar de usuario
placas

Porque Implementación de QuerySets el pitón __or__ operador (|), o unión, simplemente funciona. Como era de esperar, el | operador binario devuelve un QuerySet asi que order_by(), .distinct()y otros filtros de conjuntos de consultas se pueden agregar al 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 el Referencia de la API de Django 2.1 QuerySet. Más discusión histórica se puede encontrar en Boleto del Proyecto Django #21333.

  • “indocumentado” y “heredado” me dan miedo. Creo que es más seguro usar el objeto Q, como se detalla en la respuesta aceptada aquí.

    – 0atman

    3 de julio de 2014 a las 10:42

  • FYI, order_by() y distint() se pueden aplicar al conjunto de consultas canalizado después de que se combinen

    – carruthd

    15/07/2014 a las 14:00

  • @Oatman: | el operador está documentado. Ver docs.djangoproject.com/en/2.0/ref/models/querysets: “En general, los objetos Q() hacen posible definir y reutilizar condiciones. Esto permite la construcción de consultas de base de datos complejas utilizando los operadores | (OR) y & (AND); en particular, de otro modo no es posible utilizar OR en conjuntos de consultas”. No revisé la documentación de versiones anteriores, pero el operador de tubería funciona al menos desde Django 1.1.4 (solo lo intenté).

    – hacerooo

    31 de enero de 2018 a las 14:50

  • No @OsmanHamashool, creo que es una mala idea. Utiliza el incorporado de python set constructor para deduplicar el conjunto de consultas de su base de datos. Siempre usa .distinct() en su conjunto de consultas en su lugar. Eso se ejecutará de manera más eficiente dentro de su base de datos (SQL) y no sobrecargará su proceso de python. La próxima vez, haz un duckup con “django queryset unique” para encontrar el .distinct() método en los documentos de Django.

    – placas

    5 de noviembre de 2021 a las 22:15

  • @hobs gracias, hay otra desventaja de usar python set, que es que no puede ordenar sus conjuntos de consultas. Estoy planeando cambiar a postgres ahora, lo probaré nuevamente y actualizaré el resultado aquí.

    – Osman Hamashool

    8 de noviembre de 2021 a las 14:58


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 es preferible.

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

los Libro de cocina Django ORM habla con cierto 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-libro de cocina


avatar de usuario
faiz hameed

Solo agregando esto para múltiples filtros adjuntos a Q objeto, si alguien podría estar buscándolo. si un Q se proporciona el objeto, debe preceder a la definición de cualquier argumento de palabra clave. De lo contrario, es una consulta no válida. Debes tener cuidado al hacerlo.

un ejemplo seria

from django.db.models import Q
User.objects.filter(Q(income__gte=5000) | Q(income__isnull=True),category='income')

Aquí se tiene en cuenta la condición OR y un filtro con categoría de ingreso

Para agregar las condiciones como “O” o “Y” como las usamos en las consultas sql, tenemos esta forma como ejemplo

from django.db.models import Q
Poll.objects.get(Q(question__startswith="Who"),Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

esto es equivalente a esta consulta sql

SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date="2005-05-02" OR pub_date="2005-05-06")

Espero que pueda entender esto correctamente: “,” es para el operador “AND” y “|” es para el operador “OR” usado en django.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad