预取在多对一关系之后相关

时间:2017-05-19 12:47:15

标签: django django-admin django-queryset

我有以下(简化)模型结构:

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

错误,因为属性与文章是多对一的关系。

1 个答案:

答案 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