Django使用对象注释查询集

时间:2019-09-02 11:55:18

标签: python django django-rest-framework

我有名为产品,材料和标签的模型。每种产品都有很多材料,每种材料都有很多标签。每个产品都有标签(不是实际关系),标签定义为产品材料的所有不同标签。我想将带有标签属性的Product queryset传递给django rest序列化器,而不会出现N + 1问题。

我使用了子查询,但是它只返回一行和一列。我试图在python级别上操作它,但是它会产生N + 1问题,即使我设法避免了N + 1问题,它也会比使用ORM慢,因为它是python。我尝试添加与产品相关的标签,并在每次更改材料和/或材料的标签时进行更新,并使用prefetch_related查询它,因此它没有N + 1,它的效果很好,但是为我的代码添加了更多的复杂性这么简单。因此,我不想在产品中添加标签关系。

class Product(models.Model):
    name = models.CharField(max_length=255)

class Material(models.Model):
    name = models.CharField(max_length=255)
    product = models.ForeignKey(Product, related_name='materials', on_delete=models.CASCADE)

class Tag(models.Model):
    name = models.CharField(max_length=255)
    material = models.ForeignKey(Material, related_name='tags', on_delete=models.CASCADE)

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = '__all__'

class ProductSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True)
    class Meta:
        model = Product
        fields = '__all__'

我希望查询集可以传递给ProductSerializer,而不会出现N + 1问题,并且无需使用信号。

1 个答案:

答案 0 :(得分:3)

您不需要自己加载相关对象。 Django有工具为您做到这一点。您可以使用.prefetch_related(..) [Django-doc]。这将使查询通过附加查询来检索相关对象,然后将这些对象链接到相关对象。因此,它基本上在Python / Django端执行JOIN,并且仅对这些JOIN使用恒定数量的查询:

products = Product.objects.prefetch_related('materials__tags')
serializer = ProductSerializer(products, many=True)

因此,在此我们避免使用另一个查询为每个tags提取Product