You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React购物车订单提交遇TypeError,后端items数组为空问题求助

问题解决:React+Django REST Framework订单提交时items为空及类型错误

问题描述

开发React购物车功能,后端基于Django REST Framework,定义OrderedItem和Order模型分别存储订单项与订单。前端提交订单时,发送的数据格式看似正常,但后端接收的items数组为空,同时触发错误:

TypeError: Field 'id' expected a number but got OrderedDict([('food', <FoodDetails: Nasi Goreng>), ('quantity', 2)])

相关代码

前端React代码

const orderedItems = await Promise.all(
  cartItems.map(async (item) => {
    const response = await fetch(
      "http://127.0.0.1:8000/api/menu/fooddetails/" + item.id
    );
    const food = await response.json();
    const orderedItem: OrderedItem = {
      food: food.food_id,
      quantity: item.quantity,
    };
    return orderedItem;
  })
);

const order: IOrderData = {
  items: orderedItems,
  total_price: totalAmount,
  total_items: totalQuantity,
};

const response = await fetch("http://127.0.0.1:8000/api/order/", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify(order),
});

const data = await response.json();
console.log(data);

Django后端代码

models.py

from menu.models import FoodDetails

class OrderedItem(models.Model):
    food = models.ForeignKey(FoodDetails, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

    def __str__(self):
        return str(self.food.food_name)
    
class Order(models.Model):
    order_id = models.AutoField(primary_key=True)
    items = models.ManyToManyField(OrderedItem)
    total_price = models.PositiveIntegerField()
    total_items = models.PositiveIntegerField()
    order_status = models.CharField(default='Pending', max_length=255)
    ordered_date = models.DateField(auto_now_add=True)
    ordered_time = models.TimeField(auto_now_add=True)

    def __str__(self):
        return str(self.order_id)

serializers.py

class OrderedItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderedItem
        fields = ('food', 'quantity')

class OrderSerializer(serializers.ModelSerializer):
    items = OrderedItemSerializer(many=True)

    class Meta:
        model = Order
        fields = ('order_id', 'items', 'total_price', 'total_items', 'order_status', 'ordered_date', 'ordered_time')
    
    def create(self, validated_data):
        items = validated_data.pop('items', [])
        print(items)
        order = Order.objects.create(**validated_data)
        for item in items:
            order.items.add(item)
        return order

views.py

from rest_framework import generics
from .serializers import OrderSerializer, OrderedItemSerializer
from .models import Order, OrderedItem

class OrderList(generics.ListCreateAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

class OrderDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    
class OrderedItemList(generics.ListCreateAPIView):
    queryset = OrderedItem.objects.all()
    serializer_class = OrderedItemSerializer

class OrderedItemDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = OrderedItem.objects.all()
    serializer_class = OrderedItemSerializer

错误原因

  1. ManyToMany字段关联逻辑错误:Order模型的items是ManyToManyField,关联的OrderedItem必须是已保存到数据库的实例。当前代码直接将验证后的OrderedDict对象传入order.items.add(),而非合法的模型实例,导致类型错误。
  2. 模型设计不合理:业务上一个订单项仅属于一个订单,使用ManyToManyField不符合实际场景,应该用ForeignKey关联Order和OrderedItem。

解决方案

方案一:修正序列化器逻辑(适配现有模型)

修改serializers.py中的OrderSerializer的create方法,先创建OrderedItem实例再关联到订单:

class OrderSerializer(serializers.ModelSerializer):
    items = OrderedItemSerializer(many=True)

    class Meta:
        model = Order
        fields = ('order_id', 'items', 'total_price', 'total_items', 'order_status', 'ordered_date', 'ordered_time')
    
    def create(self, validated_data):
        items_data = validated_data.pop('items')
        order = Order.objects.create(**validated_data)
        for item_data in items_data:
            # 先创建订单项实例
            ordered_item = OrderedItem.objects.create(**item_data)
            # 关联到订单
            order.items.add(ordered_item)
        return order

方案二:优化模型设计(推荐)

调整模型关系,让OrderedItem通过ForeignKey关联Order,更符合业务逻辑:

修改models.py

class Order(models.Model):
    order_id = models.AutoField(primary_key=True)
    total_price = models.PositiveIntegerField()
    total_items = models.PositiveIntegerField()
    order_status = models.CharField(default='Pending', max_length=255)
    ordered_date = models.DateField(auto_now_add=True)
    ordered_time = models.TimeField(auto_now_add=True)

    def __str__(self):
        return str(self.order_id)

class OrderedItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
    food = models.ForeignKey(FoodDetails, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()

    def __str__(self):
        return str(self.food.food_name)

修改serializers.py

class OrderedItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderedItem
        fields = ('food', 'quantity')

class OrderSerializer(serializers.ModelSerializer):
    items = OrderedItemSerializer(many=True)

    class Meta:
        model = Order
        fields = ('order_id', 'items', 'total_price', 'total_items', 'order_status', 'ordered_date', 'ordered_time')
    
    def create(self, validated_data):
        items_data = validated_data.pop('items')
        order = Order.objects.create(**validated_data)
        # 创建订单项时直接关联订单
        for item_data in items_data:
            OrderedItem.objects.create(order=order, **item_data)
        return order

前端优化(可选)

如果购物车项中已包含食品ID,无需额外请求食品详情接口,直接构造订单项数据:

// 假设cartItems中的item.id就是food_id
const orderedItems = cartItems.map(item => ({
  food: item.id,
  quantity: item.quantity
}));

测试验证

修改代码后重启Django服务,前端提交订单,后端将正常创建订单及关联订单项,不再出现类型错误和items为空的问题。

内容的提问来源于stack exchange,提问作者doop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:09:59