我有以下(简化)模型结构:
php/console list
在管理面板中,我想显示100个文章的列表并显示其article_number。这现在导致100次数据库调用(我可以使用Silk监视看到),所以我想预取这些对象。我在管理面板中尝试了以下解决方案,但都没有用。在这里减少数据库调用次数的正确方法是什么?
我正在使用带有PostgreSQL后端的Django 1.8.14。
不起作用的解决方案:
class Article(Model):
@property
def article_number(self) -> str:
return self.attributes.get(masterdata_type__code='article_number').value
class Attribute(Model):
article = ForeignKey(Article, null=True, blank=True, related_name='attributes')
masterdata_type = ForeignKey(Type, related_name='attributes')
value = CharField(max_length=256, blank=True, db_index=True)
class Type(Model):
code = models.CharField(max_length=32)
仍有100多个数据库调用。
def get_queryset(self, request):
queryset = super(ArticleSetAdmin, self).get_queryset(request)
return queryset.prefetch_related('attributes__masterdata_type')
仍有100多个数据库调用。
def get_queryset(self, request):
queryset = super(ArticleSetAdmin, self).get_queryset(request)
return queryset.prefetch_related(
Prefetch('attributes', queryset=Attribute.objects.select_related('masterdata_type')))
仍有100多个数据库调用。
def get_queryset(self, request):
queryset = super(ArticleSetAdmin, self).get_queryset(request)
return queryset.prefetch_related(
Prefetch('attributes', queryset=Attribute.objects.prefetch_related('masterdata_type')))
错误,因为属性与文章是多对一的关系。
答案 0 :(得分:2)
您需要在Prefetch
对象中过滤查询集,否则get()
中的article_number
会导致新查询。
def get_queryset(self, request):
queryset = super(ArticleSetAdmin, self).get_queryset(request)
return queryset.prefetch_related(
Prefetch(
'attributes',
queryset=Attribute.objects.filter(masterdata_type__code='article_number'),
to_attr=article_number_attributes,
)
)
我已使用to_attr
参数,因此我们不会使用已过滤的查询集覆盖attributes
。然后,您需要更新article_number
以使用新属性。
@property
def article_number(self):
return self.article_number_attributes[0].value