为什么Django admin中的list_select_related在这种情况下不起作用?
我有一个 ModelAdmin
类,它的 list_display
中包含一个外键字段。但是,这个模型的管理列表页面每一行都要进行数百次查询,每行都要从另一个表获取数据,而不是使用连接查询(select_related()
)。
根据Django的文档,你可以在你的ModelAdmin中添加一个属性 list_select_related = True
来解决这个问题,但对我来说似乎完全没用。这个StackOverflow的问题似乎也遇到了类似的问题,但他的解决办法不太清楚,而且在我这里也不管用。
这是我模型和模型管理的简化版本:
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
然而,添加 list_selected_related = True
并没有改变任何事情。我仍然看到很多这样的查询,而不是一个SQL连接:
有没有人知道为什么Django管理界面似乎忽略了我的list_select_related,导致进行了N次查询?我使用的是Python 2.7和Django 1.3.3。
3 个回答
虽然一般情况下使用 select_related
是比较好的选择,但有时候我们需要更多的控制权,这时候重写 get_queryset
就更合适了。这是对 Daniel Roseman 答案的一个更现代的版本:
这里的 foo
和 bar
是外键字段:
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('foo', 'foo__bar').only('foo__field1', 'foo__bar__field2')
自从Django 1.6版本开始,list_select_related
这个选项可以接受一个布尔值、列表或者元组,里面包含你想要在select_related()
调用中包含的字段名。
class EventAdmin(admin.ModelAdmin):
list_display = ('__str__', 'device')
list_select_related = ['device']
这里的问题是,设置 list_select_related = True
只是给查询添加了一个基本的 select_related()
,但是这个调用默认情况下不会跟踪那些设置了 null=True
的外键(ForeignKey)。所以解决办法是自己定义一下 changelist 使用的查询集,并明确指定要跟踪的外键:
class EventAdmin(admin.ModelAdmin):
list_display = ('__str__', 'device')
def queryset(self, request):
return super(EventAdmin, self).queryset(request).select_related('device')