django Rest Framework Serializer.data 抛出有关多关系中属性的错误

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

我有以下型号:

class MenuItem(models.Model):

    class Category(models.TextChoices):
        PIZZA = "pizza"
        SIDE = "side"
        OTHER = "other"
    
    name = models.CharField(max_length=40)
    description = models.TextField(max_length=150)
    price = models.FloatField(default=0.0)
    category = models.CharField(max_length=50, choices=Category.choices, default=Category.OTHER)

class Order(models.Model):

    class OrderStatus(models.TextChoices):
        NEW = "new"
        READY = "ready"
        DELIVERED = "delivered"

    customer = models.CharField(max_length=50)
    order_time = models.DateTimeField(auto_now_add=True)
    items = models.ManyToManyField(MenuItem, through='OrderItem')
    status = models.CharField(max_length=50, choices=OrderStatus.choices, default=OrderStatus.NEW)

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

以及以下序列化器:

class MenuItemSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=40)
    description = serializers.CharField(max_length=150)
    price = serializers.FloatField(default=0.0)
    category = serializers.CharField(max_length=50)
    
    def create(self, validated_data):
        return MenuItem.objects.create(**validated_data)

class OrderItemSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    menu_item_id = serializers.PrimaryKeyRelatedField(queryset=MenuItem.objects.all(), source='menu_item', read_only=False)
    quantity = serializers.IntegerField(min_value=0)

class OrderSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    customer = serializers.CharField(max_length=50)
    order_time = serializers.DateTimeField(read_only=True)
    items = OrderItemSerializer(many=True)

    def create(self, validated_data):
        order_items_data = validated_data.pop('items')
        order = Order.objects.create(**validated_data)
        for order_item_data in order_items_data:
            quantity = order_item_data.pop('quantity')
            menu_item = order_item_data.pop('menu_item')
            OrderItem.objects.create(order=order, quantity=quantity, menu_item=menu_item)
        return order

然后在视图中:

@csrf_exempt
def order(request):
    if request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = OrderSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        print(serializer.errors)
        return JsonResponse(serializer.errors, status=400)

请求示例如下:

echo -n '{"customer": "John Doe", "items": [{"menu_item_id": 1, "quantity": 2}, {"menu_item_id": 2, "quantity": 1}]}' | http POST http://127.0.0.1:8000/order

当调用serializer.data时,会抛出错误:

AttributeError:尝试获取值时出现 AttributeError 序列化器

menu_item_id
上的字段
OrderItemSerializer
。这 序列化器字段可能命名不正确且不匹配任何序列化器字段
MenuItem
实例上的属性或键。原始异常文本 是:“MenuItem”对象没有属性“menu_item”。

所以它经历了serializer.save(),但是serializer.data上出现了错误。无法弄清楚为什么它无法获取值

menu_item_id
,因为它应该与带有外键的
id
上的
MenuItem
相关。

python django django-models django-rest-framework manytomanyfield
1个回答
0
投票

这里的问题是您不小心将

OrderItemSerializer
应用到了错误的模型。在
OrderSerializer
中,
items
字段被定义为
OrderItemSerializer
,但模型中的
items
字段指的是
MenuItem
模型。
OrderItem
模型只是这里M2M关系的贯通模型。

这里是您需要的更新模型和序列化器。

模型.py

class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name="order_items", on_delete=models.CASCADE)
    menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

请注意,我将

related_name="order_items"
添加到将其与
Order
模型相关联的 FK 字段,以便我们可以轻松地从
OrderSerializer
引用此数据模型。

序列化器.py

class OrderSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    customer = serializers.CharField(max_length=50)
    order_time = serializers.DateTimeField(read_only=True)
    order_items = OrderItemSerializer(many=True)

    def create(self, validated_data):
        order_items_data = validated_data.pop('order_items')
        order = Order.objects.create(**validated_data)
        for order_item_data in order_items_data:
            quantity = order_item_data.pop('quantity')
            menu_item = order_item_data.pop('menu_item')
            OrderItem.objects.create(order=order, quantity=quantity, menu_item=menu_item)
        return order

我将引用

OrderItemSerializer
的字段名称更改为
order_items
,以便序列化器现在可以处理
OrderItem
对象(使用我刚刚配置的 related_name)。序列化程序现在期望在 POST 正文中接收
order_items
字段,因此请确保重新格式化您的请求。在
create
方法的第一行中,我确保我们也弹出
order_items
,而不是
items

© www.soinside.com 2019 - 2024. All rights reserved.