sql - varias - Usando django ¿cómo puedo combinar dos consultas de modelos separados en una consulta?
unir varias tablas de access en una sola (2)
En mi caso específico, tengo dos tipos de "mensajes" que necesito recuperar y paginar.
Omitamos los detalles, y solo decimos que el primer tipo está en un modelo llamado Msg1 y el otro se llama Msg2
Los campos de estos dos modelos son completamente diferentes, los únicos campos que son comunes a los dos modelos son "fecha" y "título" (y por supuesto, identificación).
Puedo obtener Msg1.objects.all()
y Msg2.objects.all()
pero ¿puedo combinar estas dos consultas en una consulta, ordenarla por fecha y paginarla?
Necesito preservar la naturaleza perezosa de la consulta.
La solución trivial es list(query)
ambas consultas y combinarlas en una lista de Python. pero esto es ineficiente por razones obvias.
Revisé las referencias de django en modelos y dp-api, pero no parece que haya una forma de combinar consultas de diferentes modelos / tablas en una sola.
"¿combinar estas dos consultas en una consulta, ordenarla por fecha y paginarla?"
Esa es la unión de SQL. Deje el ORM de Django y use una unión SQL. No es brillantemente rápido porque SQL tiene que crear un resultado temporal, que ordena.
Crea el resultado temporal, que puede ser ordenado. Como una lista tiene un método de clasificación, deberá fusionar los dos resultados en una lista.
Escriba un algoritmo de combinación que acepte dos conjuntos de consultas, paginando los resultados.
Editar. Aquí hay un algoritmo de fusión.
def merge( qs1, qs2 ):
iqs1= iter(qs1)
iqs2= iter(qs2)
k1= iqs1.next()
k2= iqs2.next()
k1_data, k2_data = True, True
while k1_data or k2_data:
if not k2_data:
yield k1
try:
k1= iqs1.next()
except StopIteration:
k1_data= False
elif not k1_data:
yield k2
try:
k2= iqs2.next()
except StopIteration:
k2_data= False
elif k1.key <= k2.key:
yield k1
try:
k1= iqs1.next()
except StopIteration:
k1_data= False
elif k2.key < k1.key: # or define __cmp__.
yield k2
try:
k2= iqs2.next()
except StopIteration:
k2_data= False
else:
raise Exception( "Wow..." )
Puedes doblar en la paginación:
def paginate( qs1, qs2, start=0, size=20 ):
count= 0
for row in merge( qs1, qs2 ):
if start <= count < start+size:
yield row
count += 1
if count == start+size:
break
Sugeriría que use la herencia del Modelo .
Crea un modelo base que contenga fecha y título. La subclase Msg1 y Msg2 se desactivan como se describe. Realice todas sus consultas (para llenar una página) usando el modelo base y luego cambie al tipo derivado en el último momento.
Lo realmente bueno de la herencia es que django le permite usar el modelo base en claves externas de otros modelos, para que pueda hacer toda su aplicación más flexible. Debajo del capó, solo hay una tabla para el modelo base con una tabla por submodelo que contiene claves uno a uno.