2011-03-03 334 views
0

Django的1.2.5 的Python:2.5.5Django管理list_display与外键古怪慢

我的运动模式的管理员列表刚刚消失很慢(5分钟400条记录)。它在一秒钟之内回归,直到我们有400场比赛,50场奇数队和2场运动。

我修复了一个可怕的方式,所以我想看看是否有人以前见过这个。我的应用看起来像这样:

models: 

Sport(models.Model) 
    name 

Venue(models.Model) 
    name 

Team(models.Model) 
    name 

Fixture(models.Model) 
    date 
    sport = models.ForeignKey(Sport) 
    venue = models.ForeignKey(Venue) 

TeamFixture(Fixture) 
    team1 = models.ForeignKey(Team, related_name="Team 1") 
    team2 = models.ForeignKey(Team, related_name="Team 2") 


admin: 

TeamFixture_ModelAdmin (ModelAdmin) 
    list_display = ('date','sport','venue','team1','team2',) 

如果我从list_display中删除任何外键,那么它很快。只要我添加任何外键然后慢。

models: 

TeamFixture(Fixture) 
    team1 = models.ForeignKey(Team, related_name="Team 1") 
    team2 = models.ForeignKey(Team, related_name="Team 2") 
    sport_name = "" 
    venue_name = "" 
    team1_name = "" 
    team2_name = "" 

    def __init__(self, *args, **kwargs): 
     super(TeamFixture, self).__init__(*args, **kwargs) 

     self.sport_name = self.sport.name 
     self.venue_name = self.venue.name 
     self.team1_name = self.team1.name 
     self.team2_name = self.team2.name 

admin: 

TeamFixture_ModelAdmin (ModelAdmin) 
    list_display = ('date','sport_name','venue_name','team1_name','team2_name',) 

管理所有其他型号的罚款几千上万条记录的时刻,并在实际的所有观点:

我通过在模型初始化使用非外键,但计算它们所以此工程在固定它网站运行良好。

回答

3

我会寻找的第一件事是数据库调用。如果您不应该那样做,请安装django-debug-toolbar。这个很棒的工具可以让你检查为当前请求完成的所有sql查询。我认为有很多。如果你看他们,你会知道在哪里寻找问题。

我自己遇到的一个问题是:当模型的__unicode__方法使用外键时,会导致每个实例有一个数据库命中。我知道两种方法来解决这个问题:

  • 使用select_related,这通常是你最好的选择。
  • 使您的__unicode__返回一个静态字符串并覆盖save方法来相应地更新此字符串。
+0

此外,您可以在unicode函数中注意调用外键unicode函数。这些导致进一步的子查询。 – 2012-03-19 16:38:12

3

这让我疯狂。 list_select_related设置为True,但是在list_display中向用户添加外键会在admin中为每行生成一个查询,这会使列表变慢。 Select_related是True,所以Django管理员不应该在每一行调用这个查询。 发生了什么事?

+0

史蒂夫K你有没有得到这个固定的?我完全相同,并且疯了...... – 2013-12-20 17:55:43

+1

是的,我在2年前就修好了。您的'ModelAdmin'需要重写'get_queryset'(参见文档)以添加'select_related()'语句。你也可以使用'only'和'defer'字段,任何你想要的。 – 2013-12-23 01:44:08

+0

Thankyou @ steve-k感谢你我可能会花一些时间与我的家人在这个圣诞节。 – 2013-12-23 15:16:35

0

这是Django管理员和外键的一个很老的问题。这里发生的是,当你尝试加载一个对象时,它会试图获取该外键的所有对象。所以我们可以说你正在试图加载一些球队的球员(比如说球队的数量约为100),它会一直保持包括所有的100支球队。您可以尝试使用称为raw_fields的东西来优化它们。这样做不是必须一次调用所有内容,而是要限制调用的次数,并确保只有在事件触发时(即选择团队时)才能进行调用。 如果这看起来有点像一个UI一塌糊涂,你可以尝试使用这个类:

""" 
For Raw_id_field to optimize django performance for many to many fields 
""" 
class RawIdWidget(ManyToManyRawIdWidget): 
    def label_for_value(self, value): 
     values = value.split(',') 
     str_values = [] 
     key = self.rel.get_related_field().name 
     for v in values: 
      try: 
       obj = self.rel.to._default_manager.using(self.db).get(**{key: v}) 
       x = smart_unicode(obj) 
       change_url = reverse(
        "admin:%s_%s_change" % (obj._meta.app_label, obj._meta.object_name.lower()), 
        args=(obj.pk,) 
       ) 
       str_values += ['<strong><a href="%s">%s</a></strong>' % (change_url, escape(x))] 
      except self.rel.to.DoesNotExist: 
       str_values += [u'No input or index in the db'] 
     return u', '.join(str_values) 

class ImproveRawId(admin.ModelAdmin): 
    raw_id_fields = ('created_by', 'updated_by') 
    def formfield_for_dbfield(self, db_field, **kwargs): 
     if db_field.name in self.raw_id_fields: 
      kwargs.pop("request", None) 
      type = db_field.rel.__class__.__name__ 
      kwargs['widget'] = RawIdWidget(db_field.rel, site) 
      return db_field.formfield(**kwargs) 
     return super(ImproveRawId, self).formfield_for_dbfield(db_field, **kwargs) 

只要确保你正确地继承类。我猜想像TeamFixture_ModelAdmin (ImproveRawIdFieldsForm)。这很可能会在你的django管理中给你一个非常酷的性能提升。