可以覆盖管理模型的get_queryset
方法;我用它来选择/预取OneToOneField
或ManyToManyField
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')
行仅与更改/添加视图相关?
答案 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
上的完整演示应用