Django admin list_display 使用外键时异常缓慢

发布于 2024-10-20 06:23:11 字数 1451 浏览 1 评论 0原文

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

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

Django 1.2.5
Python: 2.5.5

My admin list of a sports model has just gone really slow (5 minutes for 400 records). It was returning in a second or so until we got 400 games, 50 odd teams and 2 sports.

I have fixed it in an awful way so I'd like to see if anyone has seen this before. My app looks like this:

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

If I remove any foreign keys from list_display then it's quick. As soon as I add any foreign key then slow.

I fixed it by using non foreign keys but calculating them in the model init so this works:

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

Administration for all other models are fine with several thousand records at the moment and all views in the actual site is functioning fine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蒗幽 2024-10-27 06:23:11

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

It's driving me crazy. list_select_related is set to True, however adding a foreign key to User in the list_display generates one query per row in the admin, which makes the listing slow. Select_related is True, so the Django admin shouldn't call this query on each row.
What is going on ?

抠脚大汉 2024-10-27 06:23:11

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

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

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

The first thing I would look for, are the database calls. If you shouldn't have done that already, install django-debug-toolbar. That awesome tool lets you inspect all sql queries done for the current request. I assume there are lots of them. If you look at them, you will know where to look for the problem.

One problem I myself have run into: When the __unicode__ method of a model uses a foreign key, that leads to one database hit per instance. I know of two ways to overcome this problem:

  • use select_related, which usually is your best bet.
  • make your __unicode__ return a static string and override the save method to update this string accordingly.
谁许谁一生繁华 2024-10-27 06:23:11

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

This is a very old problem with django admin and foreign keys. What happens here is that whenever you try to load an object it tries to get all the objects of that foreign key. So lets say you are trying to load a fixture with a some teams (say the number of teams is about 100), its going to keep on including all the 100 teams in one go. You can try to optimize them by using something called as raw_fields. What this would do is instead of having to calling everything at once, it will limit the number of calls and make sure that the call is only made when an event is triggered (i.e. when you are selecting a team).
If that seems a bit like a UI mess you can try using this class:

"""
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)

Just make sure that you inherit the class properly. I am guessing something like TeamFixture_ModelAdmin (ImproveRawIdFieldsForm). This will most likely give you a pretty cool performance boost in your django admin.

咿呀咿呀哟 2024-10-27 06:23:11

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

I fixed my problem by setting list_select_related to the list of related model fields instead of just True

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文