Django Admin中列表视图和更改视图的不同查询集优化

时间:2016-10-15 02:23:34

标签: django-admin

可以覆盖管理模型的get_queryset方法;我用它来选择/预取OneToOneFieldManyToManyField s的对象。但是,我的模型的列表视图仅显示简洁信息,而更改视图包含更多对象。如果这些关系无法显示,则在列表视图中预取ManyToManyField关系是没有意义的。

样本模型:

class Location(TimeStampedModel):
    owner = models.ForeignKey('Profile', on_delete=models.CASCADE)
    postcode = models.CharField("postcode", max_length=11, blank=True)
    tenants = models.ManyToManyField('Profile', blank=True)

示例管理模型:

@admin.register(Location)
class LocationAdmin(admin.ModelAdmin):
    list_display = ('owner', 'postcode')
    fields = ('owner', 'postcode', 'tenants')
    filter_horizontal = ('tenants',)

    def get_queryset(self, request):
        qs = super(LocationAdmin, self).get_queryset(request).select_related('owner__user')
        qs = qs.prefetch_related('tenants')
        return qs

是否可以为模型的列表视图返回的查询集定义不同的优化,并为同一模型的更改/添加视图返回的查询集?

也就是说,在上面的示例管理模型中,qs.prefetch_related('tenants')行仅与更改/添加视图相关?

1 个答案:

答案 0 :(得分:1)

实现此目的的最简单方法是使用request.resolver_match属性,该属性可用于确定您正在执行的视图。以下是有点hacky / fragile(它主要是使用一些内部),但有效:

class LocationAdmin(admin.ModelAdmin):
    list_display = ['owner', 'postcode']
    fields = ['owner', 'postcode', 'tenants']
    filter_horizontal = ['tenants']

    def get_queryset(self, request):
        qs = super(LocationAdmin, self).get_queryset(request)
        qs = qs.select_related('owner__user')
        if request.resolver_match.func.__name__ == 'change_view':
            qs = qs.prefetch_related('tenants')
        return qs

您还应该考虑是否需要它以及它是否真的有效。更改视图仅显示一个主对象,这意味着对象列表的N + 1问题通常不适用。此外,内联的查询以及外键和多对多字段的小部件可能不会使用您从get_queryset提供的查询集。对于这种情况,使用Django 1.10.2进行测试,prefetch_related调用并没有减少“更改”的查询数量。查看已执行。 '添加'视图根本没有使用get_queryset方法。

请参阅https://bitbucket.org/spookylukey/djangoadmintips/src/default/queryset_optimization/?at=default

上的完整演示应用