Usando o Django como posso combinar duas consultas de modelos separados em uma consulta?

votos
12

No meu caso específico, eu tenho dois tipos de mensagens que eu preciso para resgate e paginar.

Vamos omitir os detalhes, e apenas dizer que o primeiro tipo está em um modelo chamado Msg1 e o outro é chamado MSG2

Os campos de estes dois modelos são completamente diferentes, os únicos campos que são comuns aos dois modelos são data e título (e, claro, id).

Posso obter Msg1.objects.all()e Msg2.objects.all()mas eu pode combinar essas duas consultas em uma consulta, classificá-lo por data, e paginar-lo?

Eu preciso para preservar a natureza preguiçosa da consulta.

A solução trivial é a list(query)ambas as consultas e combiná-los em uma lista de python. mas isso é ineficiente por razões óbvias.

Eu olhei através das referências Django em modelos e dp-api, mas não parece que há uma maneira de combinar consultas de diferentes modelos / tabelas em uma.

Publicado 24/11/2008 em 00:58
fonte usuário
Em outras línguas...                            


2 respostas

votos
11

Eu sugeriria que você usa herança Modelo .

Criar um modelo básico que contém data e título. Subclasse Msg1 e MSG2 off-a como descrito. Não todas as suas consultas (para encher uma página), utilizando o modelo de base e depois mudar para o tipo derivado no último momento.

A coisa realmente grande sobre herança é que Django então permite que você use o modelo de base em chaves estrangeiras de outros modelos, para que possa fazer a sua inscrição inteiro mais flexível. Sob o capô é apenas uma tabela para o modelo de base com uma tabela por sub-modelo contendo um-para-um chaves.

Respondeu 24/11/2008 em 01:35
fonte usuário

votos
2

"Combinar essas duas consultas em uma consulta, classificá-lo por data, e paginar-lo?"

  1. Essa é a união SQL. Deixe o Django ORM e usar uma união SQL. Não é brilhantemente rápido porque SQL tem para criar um resultado temporário, que ele classifica.

  2. Criar o resultado temporário, que podem ser classificados. Uma vez que uma lista tem um método de ordenação, você vai ter que mesclar os dois resultados em uma única lista.

  3. Escrever um algoritmo de mesclagem que aceita dois conjuntos de consulta, paginar os resultados.


Editar. Aqui está um algoritmo de merge.

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..." )

Você pode dobrar em pagination:

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
Respondeu 24/11/2008 em 01:10
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more