2014-11-25 15 views
12

Wenn meine Modelle wie folgt aussehen:prefetch_related für mehrere Ebenen

class Publisher(models.Model): 
    pass 

class Book(models.Model): 
    publisher = models.ForeignKey(Publisher) 

class Page(models.Model): 
    book = models.ForeignKey(Book) 

und ich möchte den queryset für Publisher ich Publisher.object.all() tun bekommen. Wenn dann sicherstellen möchten, kann ich Prefetch tun:

Publisher.objects.all().prefetch_related('book_set')` 

Meine Fragen sind:

  1. Gibt es eine Möglichkeit, diese Prefetching zu tun select_related oder ich mit prefetch_related verwenden müssen?
  2. Gibt es eine Möglichkeit, die page_set vorab abzurufen? Dies funktioniert nicht:

Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')

Antwort

19
  1. Nein, Sie nicht select_related für eine umgekehrte Beziehung verwenden können. select_related führt einen SQL-Join aus, sodass ein einzelner Datensatz im Hauptabfragesatz in der entsprechenden Tabelle genau auf einen Verweis verweisen muss (ForeignKey oder OneToOne Felder). prefetch_related führt tatsächlich eine völlig separate zweite Abfrage durch, speichert die Ergebnisse zwischen und verbindet sie dann in python mit dem Abfrage-Set. So wird es für ManyToMany oder umgekehrte ForeignKey Felder benötigt.

  2. Haben Sie zwei Unterstriche versucht, die Prefetch-Funktionen auf mehreren Ebenen auszuführen? Wie folgt aus: Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')

+3

2. Der doppelte Unterstrich funktioniert. –

+0

1. Wenn 'Page' ein' OneToOne' Feld muss 'TextContent', wäre es:' ... prefetch_related ('book_set__page_set__text_contents') 'oder' ... select_related ('book_set__page_set__text_contents') ' –

+0

ich glaube, es würde sei die zweite Version. – jproffitt

4

Da Django 1.7, Instanzen von django.db.models.Prefetch Klasse kann als Argument von .prefetch_related verwendet werden. Prefetch Objektkonstruktor hat ein Argument, das queryset nested mehrere Ebenen Prefetches so festlegen können:

Project.objects.filter(
     is_main_section=True 
    ).select_related(
     'project_group' 
    ).prefetch_related(
     Prefetch(
      'project_group__project_set', 
      queryset=Project.objects.prefetch_related(
       Prefetch(
        'projectmember_set', 
        to_attr='projectmember_list' 
       ) 
      ), 
      to_attr='project_list' 
     ) 
    ) 

es in Attribute mit _list Suffix gespeichert ist, weil ich ListQuerySet verwenden prefetch Ergebnisse zu verarbeiten (Filter/order).

Verwandte Themen