2012-12-20 21 views
28

diese als django Modell aus Gründen des simplcity Unter der Annahme:django können wir ein Feld in einem Prefetch-Modell verwenden?

class A(): 

    a = manytomany('B') 

class B(): 

    b = charfield() 
    z = foreignkey('C') 

class C(): 

    c = charfield() 

Können wir etwas tun, wie dies die z auch holen:

foo = A.objects.get(pk = 1).prefetch_related('a').select_related('a__z') 
+0

Dies ist alles im Handbuch abgedeckt ... https://docs.djangoproject.com/en/dev/ref/models/querysets/, aber "ja" ist die Antwort. – demux

+1

Eigentlich ist die Antwort "nein", der Aufruf "select_related" wie in der Frage geschrieben funktioniert nicht. Ich werde eine neue Antwort hinzufügen. Übrigens sollte der Aufruf "get" am Ende sein, nicht vor 'select_related' und' prefetch_related'. – koniiiik

Antwort

21

Sie benötigen nur einen prefetch_related Aufruf:

foo = A.objects.prefetch_related('a__z').get(pk=1) 

Dies wird beide Tabellen vorab abrufen. In Django 1.7+ können Sie die Leistung verbessern, indem Sie ein Prefetch Objekt verwenden, wie in koniiiik's answer.

+1

Ich dachte Prefetch bezogen funktioniert nur auf 'manytomanyfield', aber es funktioniert auch auf' Fremdschlüssel'? –

+0

Wie Arnar in den Kommentaren sagt, wird dies von den [Prefetch-bezogenen Dokumenten] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related) abgedeckt. Ihr Anwendungsfall ähnelt dem Beispiel '>>> Restaurant.objects.prefetch_related ('best_pizza__toppings')'. – Alasdair

+0

Gibt es Situationen, in denen dies nicht funktioniert? Ich habe ein Problem, bei dem Modell a einen Fremdschlüssel für b und einen Fremdschlüssel für c hat. Ich möchte c.objects.prefetch_related ('a__b') machen, aber es holt nur den Satz für a und tut nichts für b. – Adam

39

This answer ist korrekt mit Versionen von Django vor 1.7. Es erzeugt drei Abfragen: zuerst, holen Sie die Instanz von A, dann holen Sie die zugehörigen Instanzen von B und schließlich holen Sie die Instanzen von C bezogen auf diejenigen von B, die in der zweiten Abfrage geholt werden.

Vor Django 1.7, das ist das Beste, was Sie tun können, auch wenn die zweite Abfrage könnte theoretisch, wählen Sie alle B Objekte zusammen mit den dazugehörigen C Objekten durch die verbundene zForeignKey.

Beginnend mit Django 1.7 gibt es eine erweiterte django.db.models.Prefetch Klasse, die genau das ermöglicht. Mit Prefetch können Sie die queryset anpassen verwendet, um verwandte Objekte wie diese Prefetch:

foo = A.objects.prefetch_related(
    Prefetch('a', queryset=B.objects.select_related('z')) 
).get(pk=1) 

Dies führt in nur zwei Abfragen (im Gegensatz zu drei Gegensatz, wenn prefetch_related('a__z') verwenden) und lässt die Datenbank Pflege des zweiten nehmen, an der sollte Theoretisch ergibt sich eine etwas bessere Leistung.

+4

Das ist großartig! Ich wusste nichts von Prefetch. Vielen Dank. Hinweis für jeden, der es in der Zukunft verwendet: 'Prefetch 'ist im Importbereich der Modelle, also um es zu importieren, wie im Beispiel:' from django.db.models Import Prefetch' –

+1

Guter Punkt, ich habe den Import hinzugefügt Pfad zur Antwort sowie einen Link zu den Dokumenten. Danke für den Vorschlag. – koniiiik

Verwandte Themen