问题
I've got a ModelAdmin
class that includes a foreign key field in its list_display
. But the admin list page for that model is doing hundreds of queries, one query per row to get the data from the other table instead of a join (select_related()
).
The Django docs indicate you can add list_select_related = True
as an attribute to your ModelAdmin to make this go away, but it doesn't seem to work at all for me. This SO question seems to give a similar problem, but his resolution is unclear, and it doesn't work in my case.
Here's a cut-down version of my model and model admin:
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
However, adding that list_selected_related = True
didn't change anything. I still get lots of queries like this instead of an SQL join:
Any ideas why the Django admin seems to be ignoring my list_select_related and doing N queries? I'm using Python 2.7 and Django 1.3.3.
回答1:
The issue here is that setting list_select_related = True
just adds a basic select_related()
onto the query, but that call does not by default follow ForeignKeys with null=True
. So the answer is to define the queryset the changelist uses yourself, and specify the FK to follow:
class EventAdmin(admin.ModelAdmin):
list_display = ('__str__', 'device')
def queryset(self, request):
return super(EventAdmin, self).queryset(request).select_related('device')
回答2:
Since Django 1.6, list_select_related
accepts a boolean, list or tuple with the names of the fields to include in the select_related()
call.
Hence you can now use:
class EventAdmin(admin.ModelAdmin):
list_display = ('__str__', 'device')
list_select_related = ['device']
回答3:
Although select_related
is generally the way to go, there are time when one requires more control, then overiding the get_queryset
becomes more applicable, this is a more modern version of Daniel Roseman's answer:
Where foo
and bar
are foreign key fields:
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('foo', 'foo__bar').only('foo__field1', 'foo__bar__field2')
来源:https://stackoverflow.com/questions/15211799/why-does-django-admin-list-select-related-not-work-in-this-case