¿Cómo puedo encontrar la unión de dos conjuntos de consultas de Django?

3 minutos de lectura

avatar de usuario
Pablo D. Waite

Tengo un modelo de Django con dos métodos de administrador personalizados. Cada uno devuelve un subconjunto diferente de los objetos del modelo, en función de una propiedad diferente del objeto.

¿Hay alguna forma de obtener un conjunto de consultas, o simplemente una lista de objetos, esa es la unión de los conjuntos de consultas devueltos por cada método de administrador?

  • (De una respuesta eliminada) Consulte esta pregunta para ver una variación que funciona con QuerySets de diferentes modelos: stackoverflow.com/questions/431628/…

    – rnevio

    21 de marzo de 2016 a las 13:20

  • A partir de la versión 1.11, los conjuntos de consultas de Django tienen un método de unión incorporado. Lo he agregado como respuesta para futuras referencias.

    – José Cherián

    9 de agosto de 2017 a las 1:44

avatar de usuario
Jordán Reiter

Esto funciona y se ve un poco más limpio:

records = query1 | query2

Si no desea duplicados, deberá agregar .distinct():

records = (query1 | query2).distinct()

  • Si bien la respuesta aceptada devuelve una unión iterable (lista para ser exactos), como OP ha pedido, este método devuelve una verdadera unión de conjuntos de consultas. Este conjunto de consultas se puede operar más, lo que se desea en muchas circunstancias.

    –Krystian Cybulski

    9 de enero de 2013 a las 15:10

  • Debido a un error de Django, esta construcción a veces puede devolver resultados incorrectos cuando se trata de ManyToManyFields. Por ejemplo, a veces verás que records.count() será mayor que query1.count() + query2.count()lo cual es claramente incorrecto.

    – Jian

    24 de abril de 2013 a las 0:00

  • @Jian, ¿puede aclarar la versión de django con el error y un enlace al problema de djangoproject?

    – IMFletcher

    3 de mayo de 2013 a las 1:59

  • registros = consulta1 | consulta2; records = records.distinct() me daría el resultado correcto

    – eugene

    31 de mayo de 2013 a las 6:34

  • Puede sobrecargar los operadores en Python. Ver docs.python.org/2/library/operator.html. Entonces, lo que hace Django es crear métodos especiales para el objeto QuerySet. Ver el código aquí: github.com/django/django/blob/master/django/db/models/… la QuerySet clase proporciona métodos para __and__ y __or__ que se llaman cuando el & o | Los operadores se utilizan entre dos QuerySet objetos (también utilizados para la Q clase también).

    – Jordán Reiter

    7 oct 2013 a las 18:11

avatar de usuario
José Cherián

Empezando desde versión 1.11los conjuntos de consultas de django tienen un método de unión integrado.

q = q1.union(q2) #q will contain all unique records of q1 + q2
q = q1.union(q2, all=True) #q will contain all records of q1 + q2 including duplicates
q = q1.union(q2,q3) # more than 2 queryset union

Mira mi entrada en el blog en esto para más ejemplos.

  • No pude obtener all=True para trabajar. Terminé lanzando mi conjunto de consultas a un conjunto antes de devolverlo al cliente.

    –Braden Holt

    15 de marzo de 2019 a las 23:32

  • @BradenHolt, all=True, significa que contendrá registros duplicados. Simplemente puede eliminar all=True para evitar convertirlo en un conjunto.

    – José Cherián

    16 de marzo de 2019 a las 20:26

  • después de esto, DjangoFilterBackend no funciona, ¿cómo puedo usar union y DjangoFilterBackend?

    – nesalexia

    29 de agosto de 2019 a las 17:59

  • Desafortunadamente, esto no parece funcionar para modelos con un orden predeterminado definido en el Meta del modelo. Cada vez que trato de combinarlos con .union, recibo el siguiente error: “ORDER BY no permitido en subconsultas de declaraciones compuestas”.

    – jrial

    15 de noviembre de 2019 a las 14:29

avatar de usuario
xian xing

Yo sugeriría usar ‘query1.union(query2)’ en lugar de ‘query1 | consulta2’; Obtuve resultados diferentes de los dos métodos anteriores y el primero es lo que esperaba. Lo siguiente es lo que me había encontrado:

print "union result:"
for element in query_set1.union(query_set2):
    print element

print "| result:"
for element in (query_set1 | query_set2):
    print element

resultado:

union result:
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object
KafkaTopic object

| result:
KafkaTopic object
KafkaTopic object

¿Ha sido útil esta solución?