2008-11-23 11 views
11

Nel mio caso specifico, ho due tipi di "messaggi" che ho bisogno di ritirare e impaginare.Utilizzo di django come è possibile combinare due query da modelli separati in un'unica query?

Diamo omettere i dettagli, e solo dire che il primo tipo è in un modello chiamato Msg1 e l'altra si chiama MSG2

I campi di questi due modelli sono completamente diversi, gli unici campi che sono comuni agli due modelli sono "date" e "title" (e, naturalmente, id).

Posso ottenere Msg1.objects.all() e Msg2.objects.all() ma posso combinare queste due query in una query, ordinarla per data e impaginarla?

Ho bisogno di preservare la natura pigra della query.

La soluzione banale è a list(query) entrambe le query e combinarle in un elenco python. ma questo è inefficiente per ovvi motivi.

Ho guardato attraverso i riferimenti Django su modelli e dp-api, ma non sembra che ci sia un modo per combinare query di diversi modelli/tabelle in uno.

+0

"inefficiente per ovvi motivi" Davvero? Hai metriche? Chiedo perché non c'è una ragione ovvia per cui sarebbe inefficiente. –

+0

Penso perché una volta elencato (query) ottiene tutti i risultati, e vuole lasciarlo il più tardi possibile. –

+0

inefficiente perché colpisce il database per TUTTI gli articoli, (potrebbe essere 1000) mentre visualizza solo 20 per pagina o giù di lì .. – hasen

risposta

11

vorrei suggerire di utilizzare Model inheritance.

Creare un modello di base che contenga data e titolo. Sottoclasse Msg1 e Msg2 fuori come descritto. Fai tutte le tue domande (per riempire una pagina) usando il modello base e poi passa al tipo derivato all'ultimo momento.

La cosa veramente grandiosa dell'ereditarietà è che django consente quindi di utilizzare il modello base in chiavi esterne di altri modelli, in modo da rendere più flessibile l'intera applicazione. Sotto il cofano è solo una tabella per il modello base con una tabella per sottomodello contenente chiavi one-to-one.

+1

Cosa succede se la mia classe base è astratta? Puoi mostrare qualche esempio di codice? –

2

"combinare queste due query in una query, ordinarla per data e impaginarla?"

  1. Questa è l'unione SQL. Lascia l'ORM Django e usa un'unione SQL. Non è brillantemente veloce perché SQL deve creare un risultato temporaneo, che ordina.

  2. Creare il risultato temporaneo, che può essere ordinato. Poiché un elenco ha un metodo di ordinamento, dovrai unire i due risultati in un unico elenco.

  3. Scrivere un algoritmo di fusione che accetta due set di query, impaginando i risultati.


Modifica. Ecco un algoritmo di fusione.

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

Si può piegare in impaginazione:

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 
+0

Se si dovesse seguire questo percorso, si vorrebbe eseguire l'ordinamento prima dell'unione nell'istruzione SQL (poiché SQL può utilizzare gli indici per accelerare l'ordinamento) e si spera che sia possibile limitare i risultati di ordinamento intermedio prima dell'unione, riducendo le dimensioni di qualsiasi dato temporaneo. –

+0

Tuttavia, poiché un'unione può essere * qualsiasi * combinazione di tabelle, calcoli, valori letterali, ecc., Un'unione * deve * creare e ordinare un risultato intermedio. Forse puoi ottimizzare, ma la versione generale * deve * funzionare. –

Problemi correlati