25

Ho due modelli in Django. Il primo ha la gerarchia di quali funzioni di lavoro (posizioni) riportano a quali altre posizioni, e il secondo è le persone e quale funzione di lavoro esse tengono.select_related con chiavi esterne inverse

class PositionHierarchy(model.Model): 
    pcn = models.CharField(max_length=50) 
    title = models.CharField(max_length=100) 
    level = models.CharField(max_length=25) 
    report_to = models.ForeignKey('PositionHierachy', null=True) 


class Person(model.Model): 
    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50) 
    ... 
    position = models.ForeignKey(PositionHierarchy) 

Quando ho un record di persona e voglio trovare direttore della persona, devo fare

manager = person.position.report_to.person_set.all()[0] 
# Can't use .first() because we haven't upgraded to 1.6 yet 

Se sto ottenendo le persone con una QuerySet, posso entrare (ed evitare una secondo viaggio al database) con posizione e report_to usando Person.objects.select_related('position', 'position__reports_to').filter(...), ma c'è un modo per evitare di fare un altro viaggio nel database per ottenere la persona_set? Ho provato ad aggiungere 'position__reports_to__person_set' o semplicemente a position__reports_to__person allo select_related, ma sembra che non cambi la query. E 'questo il motivo per cui è prefetch_related?

Mi piacerebbe creare un gestore personalizzato in modo che quando faccio una query per ottenere record Person, ottengo anche la loro PositionHeirarchy e il record Person del loro manager senza ulteriori round trip nel database. Questo è quello che ho finora:

class PersonWithManagerManager(models.Manager): 
    def get_query_set(self): 
     qs = super(PersonWithManagerManager, self).get_query_set() 
     return qs.select_related(
      'position', 
      'position__reports_to', 
     ).prefetch_related(
     ) 
+0

probabilmente un errore di battitura, ma dovrebbe essere 'get_queryset()', 'non get_query_set'. – Paolo

+1

@Paolo era 'get_query_set' in Django 1.5. –

risposta

25

Sì, questo è ciò che è per prefetch_related(). Richiederà una query aggiuntiva, ma l'idea è che otterrà tutte le informazioni correlate contemporaneamente, invece di una volta per Person.

Nel tuo caso:

qs.select_related('position__report_to') 
    .prefetch_related('position__report_to__person_set') 

dovrebbe richiedere due query, indipendentemente dal numero di Persons nel set di query originale.

Confrontare questo esempio dal documentation:

>>> Restaurant.objects.select_related('best_pizza') 
         .prefetch_related('best_pizza__toppings') 
Problemi correlati