我有以下型号:
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”对象没有属性“menu_item”。MenuItem
所以它经历了serializer.save(),但是serializer.data上出现了错误。无法弄清楚为什么它无法获取值
menu_item_id
,因为它应该与带有外键的 id
上的 MenuItem
相关。
这里的问题是您不小心将
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
。