【问题标题】:Django admin list_display weirdly slow with foreign keysDjango admin list_display 使用外键异常缓慢
【发布时间】:2011-07-08 01:31:36
【问题描述】:

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 中删除任何外键,那么它很快。只要我添加任何外键就会变慢。

我通过使用非外键但在模型初始化中计算它们来修复它,所以这有效:

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

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

【问题讨论】:

    标签: python performance django-admin foreign-keys


    【解决方案1】:

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

    【讨论】:

    • Steve K 你有没有解决这个问题?我在完全相同的绑定中并且要发疯了......
    • 是的,我大约在 2 年前修复了它。您的 ModelAdmin 需要覆盖 get_queryset (请参阅文档)以添加 select_related() 语句。您还可以随意使用only 和defer 字段。
    • Thankyou @steve-k 感谢你,我可能会在这个圣诞节与家人共度时光。
    • 最好在您的模型上创建一个自定义管理器,以确保始终使用 select_related 而不是为每个查询执行 select_related
    【解决方案2】:

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

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

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

    【讨论】:

    • 另外——你可以在你的 unicode 函数中,注意调用外键 unicode 函数。这些会导致更多的子查询。
    【解决方案3】:

    这是 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 管理员带来非常酷的性能提升。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2016-01-10
        • 2019-07-28
        • 2018-02-12
        • 1970-01-01
        • 2017-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-07
        相关资源
        最近更新 更多