【问题标题】:How can I make Django use select_related() on a foreign key in the admin site?如何让 Django 在管理站点的外键上使用 select_related()?
【发布时间】:2013-01-10 09:56:33
【问题描述】:

我有几个模型:Review,其中包含专辑评论字段,Record,这是专辑名称等,Band,这是乐队名称。 Record 有一个针对 Band 的外键,Review 有一个针对 Record 的外键。

Review 的管理表单中,我想为所有Records 显示一个下拉选择框。目前,Record 的 unicode 方法只是:

def __unicode__(self):
    return self.record_name

这不是很有帮助,所以我将其更改为:

def __unicode__(self):
    return self.band.band_name + ' - ' + self.record_name  

这现在为每个Record(3000 左右)添加一个查询,显然不好。

阅读this answer,我尝试将此添加到我的模型管理员Record

def queryset(self, request):
    return super(RecordAdmin, self).queryset(request).select_related('band')

不过,这并没有什么不同。

是否可以在模型的 __unicode__ 表示中使用外键字段而不会引发 n 平方查询?

更新:这是模型(删除了不相关的字段):

class Review(models.Model):

    def __unicode__(self):
        # this is used in other places where we show review titles
        return self.record.band.band_name + ' - ' + self.record.record_name

    record = models.ForeignKey('Record')
    review_text = models.TextField()

class Record(models.Model):

    def __unicode__(self):
        # this generates a billion queries
        #return self.record_name
        return self.band.band_name + ' - ' + self.record_name  

    def band_and_title(self):
        return self.band.band_name + ' - ' + self.record_name

    band = models.ForeignKey('Band')
    label = models.ForeignKey('Label')
    record_name = models.CharField(max_length=175)

class Band(models.Model):

    def __unicode__(self):
        return self.band_name

    band_name = models.CharField(max_length=100)

【问题讨论】:

  • 您是否有更多信息:Django 版本等。我在几个地方和项目中几乎完全使用此代码,并取得了巨大成功。
  • 当然:本地版本 1.4.1(尽管服务器使用的是 1.2.3)。我把它放在正确的模型上吗?从技术上讲,我正在编辑 Review 而不是 Record,但我也在那里尝试过,没有发现任何区别。

标签: django


【解决方案1】:

鉴于您的评论,您实际上可能需要选择相关的记录和 乐队。像这样:

class ReviewAdmin(admin.ModelAdmin):
    model = Review
    def queryset(self, request):
        return super(ReviewAdmin, self).queryset(request).select_related('record', 'record__band')

class RecordAdmin(admin.ModelAdmin):
    model = Record
    def queryset(self, request):
        return super(RecordAdmin, self).queryset(request).select_related('band')

使用Django Toolbar 是发现正在运行的查询的好方法。

【讨论】:

  • 谢谢——这并没有什么不同,遗憾的是:(——有点不确定model = mymodels.Review 行,这是一个“神奇”变量吗(因为它没有在其他任何地方引用这段代码?)。我刚刚使用了model = Review(我已经在上面导入了webzine.models.Review)。
  • 这是一个风格的东西,我总是只导入模型。应该没关系。您可以将精简的对象添加到您的问题中吗?就像我说的那样,这行得通,我们只是缺少了一些东西。
【解决方案2】:

您需要在管理站点创建更改表单时注入select_related。您可以通过为您的 ModelAdmin 覆盖 ModelAdmin.formfield_for_foreignkey 来做到这一点。像这样的:

class ReviewAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "record":
            kwargs["queryset"] = Record.objects.all().select_related()

        return super(ReviewAdmin, self).formfield_for_foreignkey(
            db_field, request, **kwargs)

【讨论】:

  • 很奇怪。 formfield_for_foreignkey 根本不会启动。我正在使用 django 1.8。
猜你喜欢
  • 2016-11-22
  • 2019-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多