Django admin list_display外键很奇怪

时间:2011-03-03 13:21:04

标签: python performance django-admin foreign-keys

Django 1.2.5 Python:2.5.5

我的体育模特管理员名单刚刚变得非常缓慢(400条记录为5分钟)。它在一秒左右回来,直到我们有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中删除任何外键,那么它很快。只要我添加任何外键,然后慢一点。

我通过使用非外键修复它,但在模型init中计算它们以便这样做:

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',)

目前所有其他模型的管理都很好,有数千条记录,实际网站中的所有视图都运行良好。

4 个答案:

答案 0 :(得分:3)

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

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

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

答案 1 :(得分:3)

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

答案 2 :(得分:0)

这是django admin和外键的一个非常老的问题。这里发生的是,无论何时尝试加载对象,它都会尝试获取该外键的所有对象。因此,假设您正在尝试加载一些团队的装备(比如团队的数量大约是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管理员带来非常酷的性能提升。

答案 3 :(得分:0)

我通过将list_select_related设置为相关模型字段的列表而不是True来解决了我的问题