python DRF -使用ModelSerializer保存具有“though”表的manyToMany关系时出现AttributeError

5sxhfpxr  于 2023-03-11  发布在  Python
关注(0)|答案(1)|浏览(120)

我正在构建一个Django Rest Framework项目,遇到了一个似乎无法解决的属性错误。具体来说,当我试图序列化一个销售对象时,我遇到了以下错误:

Got AttributeError when attempting to get a value for field `product` on serializer `SaleItemSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Product` instance.
Original exception text was: 'Product' object has no attribute 'product'.

我定义了我的模型和序列化器,如下所示:

# Models
class Product(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    cost = models.DecimalField(max_digits=10, decimal_places=2)
    description = models.TextField()
    image = models.ImageField(upload_to='images/')
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Sale(models.Model):
    products = models.ManyToManyField(Product, related_name='sales', through='SaleItem')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class SaleItem(models.Model):
    sale = models.ForeignKey(Sale, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

# Serializers
class SaleItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = SaleItem
        fields = ['product', 'quantity', 'value']

class SaleSerializer(serializers.ModelSerializer):
    products = SaleItemSerializer(many=True)

    class Meta:
        model = Sale
        fields = '__all__'

    def create(self, validated_data):
        sale_items_data = validated_data.pop('products')
        sale = Sale.objects.create(**validated_data)
        for sale_item in sale_items_data:
            SaleItem.objects.create(sale=sale, **sale_item) # The erro
        return sale

我用于序列化程序的代码基本上是以下文档示例:DRF可写嵌套序列化器唯一的区别是SaleItem是manyToMany关系的Through表,而不是“普通”表。
我尝试过将SaleItem对象创建行更改为将数据传递回序列化程序,但这样序列化程序就永远不会有效,而将其更改为创建有效会破坏SaleSerializer的字段。
我怀疑问题出在SaleItemSerializer或SaleSerializer的create方法上,但我无法找出导致属性错误的原因。我现在唯一的希望是编写一个普通的Serializer和整个逻辑,但我真的想使用整个框架的潜力。

1mrurvl1

1mrurvl11#

基本上是因为你试图用SaleItem模型序列化一个Product,而且Product没有名为product的字段。
例如,您可以将相关名称添加到SaleItemsales字段:
models.py

class SaleItem(models.Model):
    sale = models.ForeignKey(
        Sale,
        on_delete=models.CASCADE,
        related_name='items'
    )
    ...

并且,使用此函数访问与该Sale示例相关的SaleItem(以及相应的Product)和SerializerMethodField:

class SaleItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = SaleItem
        fields = ['product', 'quantity', 'price']

class SaleSerializer(serializers.ModelSerializer):
    products = serializers.SerializerMethodField()

    class Meta:
        model = Sale
        fields = '__all__'

    def get_products(self, instance):
        qs = instance.items.all()
        serializer = SaleItemSerializer(qs, many=True)
        return serializer.data

另外,请注意,SaleItem中没有value字段,它被称为price
关于创建对象,这将在很大程度上取决于您发送的有效负载,这里是一个简单的例子,假设产品存在于数据库中,并且没有其他处理:
有效负载

{
    "sale_items":
    [
        {
            "product": 1,
            "quantity": 1,
            "price": 123.12
        },
        {
            "product": 2,
            "quantity": 2,
            "price": 234.23
        },
        {
            "product": 1,
            "quantity": 1,
            "price": 456.45
        }
    ]
}

然后我们可以重写ViewSet上的create方法,并通过额外的上下文将数据传递给序列化器:
views.py

class SalesViewSet(ModelViewSet):
    queryset = Sale.objects.all()
    serializer_class = SaleSerializer

    def create(self, request, *args, **kwargs):
        sale_items = request.data.pop('sale_items')
        serializer = self.get_serializer(data=request.data, context={'sale_items': sale_items})
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self. get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

serializers.py

class SaleSerializer(serializers.ModelSerializer):
    ...
    
    def get_products(self, instance):
        ...

    def create(self, validated_data):
        sale_items = self.context.get('sale_items')
        instance = Sale.objects.create(**validated_data)

        for item in sale_items:
            product_instance = Product.objects.get(id=item['product'])
            item['product'] = product_instance
            item['sale'] = instance
            SaleItem.objects.create(**item)

        return (instance)

相关问题