2013-03-04 2 views
9

Ho una classe ModelAdmin che include un campo chiave esterna nel suo list_display. Ma la pagina di elenco amministratore per quel modello sta facendo centinaia di query, una query per riga per ottenere i dati dall'altra tabella invece di un join (select_related()).Perché l'admin di Django list_select_related non funziona in questo caso?

I documenti Django indicate è possibile aggiungere list_select_related = True come attributo a ModelAdmin per farlo andare via, ma non sembra funzionare affatto per me. This SO question sembra dare un problema simile, ma la sua risoluzione non è chiara, e non funziona nel mio caso.

Ecco una versione ridotta del mio modello e il modello di amministrazione:

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 

Tuttavia, aggiungendo che list_selected_related = True non ha cambiato nulla. Ho ancora un sacco di domande come questo invece di uno SQL uniscono:

Lots of queries, not a join

Tutte le idee perché l'amministratore Django sembra ignorare i miei list_select_related e fare query N? Sto usando Python 2.7 e Django 1.3.3.

risposta

14

Il problema qui è che l'impostazione list_select_related = True aggiunge semplicemente una query di basealla query, ma quella chiamata non per impostazione predefinita segue ForeignKeys con null=True. Quindi la risposta è di definire il set di query nell'elenco modifiche usa te stesso, e specificare il FK da seguire:

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

Grazie! Il 'nullo = Vero' sulla chiave esterna stava sicuramente impedendo a selected_related di fare la sua cosa. Immagino che se avessi seguito i [documenti] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_related) fino in fondo, Avrei visto che: "Nota che, per impostazione predefinita, select_related() non segue le chiavi esterne che hanno null = True" –

+0

Fuori interesse, sai perché 'list_select_related = True' non è l'impostazione predefinita per il Django amministratore? Sembrerebbe un default molto più sensato. (Capisco perché di default 'select_related()' non segue chiavi esterne che hanno null = True, perché potrebbe essere un problema di prestazioni, ma mi chiedo a proposito di 'list_select_related' in altri casi.) –

+0

In Django> = 1.6 il metodo è ora denominato 'get_queryset'. – TAH

6

Since Django 1.6, list_select_related accetta un valore booleano, lista o tupla con i nomi dei campi da includere nella chiamata select_related(). Quindi ora puoi usare:

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