2013-03-04 10 views
9

Ich habe eine ModelAdmin Klasse, die ein Fremdschlüsselfeld in seiner list_display enthält. Die Admin-Listenseite für dieses Modell führt jedoch Hunderte von Abfragen durch, eine Abfrage pro Zeile, um die Daten aus der anderen Tabelle anstelle einer Verknüpfung abzurufen (select_related()).Warum funktioniert Django admin list_select_related in diesem Fall nicht?

Die Django-Dokumentation indicate Sie können list_select_related = True als Attribut zu Ihrem ModelAdmin hinzufügen, um dies zu entfernen, aber es scheint überhaupt nicht für mich zu arbeiten. This SO question scheint ein ähnliches Problem zu geben, aber seine Auflösung ist unklar, und es funktioniert nicht in meinem Fall.

Hier ist eine abgespeckte Version von meinem Modell und Leiter:

class Device(models.Model): 
    serial_number = models.CharField(max_length=80, blank=True, unique=True) 
    label = models.CharField(max_length=80, blank=True) 

    def __str__(self): 
     s = str(self.serial_number) 
     if self.label: 
      s += ': {0}'.format(self.label) 
     return s 

class Event(models.Model): 
    device = models.ForeignKey(Device, null=True) 
    type = models.CharField(max_length=40, null=False, blank=True, default='') 

class EventAdmin(admin.ModelAdmin): 
    list_display = ('__str__', 'device') 
    list_select_related = True 

jedoch hinzu, dass list_selected_related = True nichts geändert hat. Ich bekomme immer noch viele Anfragen wie diese anstelle einer SQL beitreten:

Lots of queries, not a join

Irgendwelche Ideen, warum die Django Admin scheint meine list_select_related und tun N Anfragen zu ignorieren? Ich benutze Python 2.7 und Django 1.3.3.

Antwort

14

Das Problem hier ist, dass die Einstellung list_select_related = True fügt einfach eine grundlegende select_related() auf die Abfrage, aber dieser Aufruf folgt standardmäßig nicht ForeignKeys mit null=True. Die Antwort ist also die queryset die Änderungsliste verwendet selbst, zu definieren und die FK angeben folgen:

class EventAdmin(admin.ModelAdmin): 
    list_display = ('__str__', 'device') 
    def queryset(self, request): 
     return super(EventAdmin, self).queryset(request).select_related('device') 
+2

Vielen Dank! Das 'null = True' auf dem Fremdschlüssel verhinderte definitiv, dass das selected_related seine Sache tat. Ich denke, wenn ich den [docs] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_related) den ganzen Weg gefolgt wäre, Ich hätte Folgendes gesehen: "Beachten Sie, dass select_related() standardmäßig keine Fremdschlüssel mit dem Wert null = True" –

+0

ist. Interessant, wissen Sie, warum 'list_select_related = True' nicht der Standardwert für Django ist Administrator? Das scheint ein viel vernünftigerer Standard zu sein. (Ich kann sehen, warum standardmäßig 'select_related()' nicht auf Fremdschlüssel folgt, die null = True haben, weil das ein Leistungsproblem sein könnte, aber ich frage mich 'list_select_related' in anderen Fällen.) –

+0

In Django> = 1.6 Die Methode heißt jetzt "get_queryset". – TAH

6

Since Django 1.6, list_select_related akzeptiert eine boolean, Liste oder Tupel mit den Namen der Felder in dem select_related() Anruf aufzunehmen. Daher können Sie jetzt verwenden:

class EventAdmin(admin.ModelAdmin): 
    list_display = ('__str__', 'device') 
    list_select_related = ['device'] 
Verwandte Themen