Django 序列化程序嵌套。如何避免对关系进行 N+1 查询。方法更新在验证中生成重复查询

问题描述 投票:0回答:0

我有以下型号:

模型

class Item(SafeDeleteModel):
    code = models.CharField(max_length=50, null=True, blank=True)
    name = models.CharField(max_length=500)
    description = models.TextField(blank=True)
    category = models.ForeignKey(Category, on_delete=models.PROTECT, null=True, blank=True)
    price = models.DecimalField(max_digits=18, decimal_places=6, default=0.0)


class PriceList(SafeDeleteModel):
    friendly_id = models.CharField(unique=True, max_length=6, null=True, blank=True, editable=False)
    code = models.CharField(max_length=10, null=True, blank=True)
    name = models.CharField(max_length=100, null=True)


class PriceListRelation(SafeDeleteModel):
    price_list = models.ForeignKey(PriceList, on_delete=models.CASCADE, related_name='price_list', null=False)
    item = models.ForeignKey(Item, on_delete=models.CASCADE,  related_name='prices_list', null=False, blank=True)
    price = models.DecimalField(max_digits=18, decimal_places=6, default=0.0)

一个商品有多个价目表关系,每个价目表关系属于一个价目表。

序列化器

class ItemSerializer(serializers.ModelSerializer):
    prices_list = PriceListRelationsSerializer(many=True, read_only=False)

    def update(self, instance, validated_data):

        if 'prices_list' in validated_data:
            prices_list = validated_data.pop('prices_list')
        else:
            prices_list = None
        instance = super().update(instance, validated_data)
        
        for price_list in prices_list:
            #code to update/create/delete price lists, this part works fine

            #Without this functionality it still duplicates the queries
        return instance


class PriceListRelationsSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=False, required=False)
    name = serializers.ReadOnlyField(source='price_list.name')
    price_list_id = serializers.PrimaryKeyRelatedField(queryset = PriceList.objects.all(), source='price_list')

视图集

class ItemsViewSet(viewsets.ModelViewSet):

    queryset = Item.objects.all().order_by('-id')
    serializer_class = ItemSerializer

    def partial_update(self, request, pk=None):
        item = Item.objects.filter(id = pk).select_related('category').prefetch_related(
             Prefetch('prices_list', queryset = PriceListRelation.objects.select_related('price_list').all()),
        ).get()
        serializer = ItemSerializer(item, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

问题 我正在尝试使用以下示例数据 PUT/PATCH 到 ItemsViewSet:

/项目/37/

{
    "name": "Item 0037",
    "price": 10,
    "category":2,
    "prices_list": [
        {
            "id": 192,
            "price_list_id": 1,
            "price": 999.97
        },
        {
            "price_list_id": 2,
            "price": 888.99
        },
        {
            "price_list_id": 2,
            "price": 234.99
        }
    ]       
}

但是,可以看出,对于添加到项目的 3 个价目表,它执行 3 个查询。如何优化?所以当元素多的时候,查询就会多

我正在使用fetch_related来优化查询(GET),有没有类似于update的东西?

查询执行详情

额外的

我明白Django验证

price_list_id
存在,我也尝试修改
PriceListRelationsSerializer
中的验证但它仍然没有优化。

以下代码执行单个查询并验证

price_list_id
,但不会删除其他单个查询

class PriceListRelationsSerializer(serializers.ModelSerializer):
    ....
    def __init__(self, *args, **kwargs):
        self.prices_list = PriceList.objects.all()
        self.prices_list = list(self.prices_list)
        super().__init__(*args, **kwargs)

    def validate_price_list_id(self, value):
        try:
            price_list = next(item for item in self.prices_list if item.name == value.name)
        except StopIteration:
            raise serializers.ValidationError('No price list'+ value)
        return price_list

任何帮助表示赞赏。 谢谢。

validation serialization django-rest-framework query-optimization nested-lists
© www.soinside.com 2019 - 2024. All rights reserved.