2013-03-04 386 views
9

我有一个ModelAdmin类,它的list_display包含一个外键字段。但该模型的管理列表页面正在执行数百个查询,每行一个查询以从另一个表中获取数据而不是连接(select_related())。为什么Django admin list_select_related在这种情况下不起作用?

Django文档indicate您可以将list_select_related = True作为属性添加到您的ModelAdmin中,以使其消失,但对我而言似乎不起作用。 This SO question似乎也给出了类似的问题,但他的决议尚不清楚,对我而言并不奏效。

这里是我的模型和模型管理的简化版本:

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的联接:

Lots of queries, not a join

任何想法,为什么Django管理似乎无视我的list_select_related和做N次查询?我使用Python 2.7和Django 1.3.3。

回答

14

问题在于设置list_select_related = True只是在查询上添加了一个基本的select_related(),但该调用默认情况下不会跟随ForeignKeys与null=True。因此,答案是确定变更列表使用自己的查询集,并指定FK遵循:

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

谢谢!外键上的'null = True'肯定会阻止selected_related做它的事情。我猜如果我一直关注[docs](https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.select_related)我会看到:“请注意,默认情况下,select_related()不遵循具有null = True的外键”“ – 2013-03-04 23:00:46

+0

出于兴趣,你知道为什么'list_select_related = True'不是Django的默认值管理员?这似乎是一个更明智的默认。 (我可以明白为什么默认'select_related()'不遵循具有null = True的外键,因为这可能是一个性能问题,但我想知道其他情况下的'list_select_related'。) – 2013-03-10 20:54:57

+0

在Django> = 1.6该方法现在被命名为'get_queryset'。 – TAH 2017-07-29 19:29:10

6

Since Django 1.6list_select_related接受一个布尔值,列表或元组与字段的名称在select_related()调用包括。 因此您现在可以使用:

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