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
错误原因
- ManyToMany字段关联逻辑错误:
Order模型的items是ManyToManyField,关联的OrderedItem必须是已保存到数据库的实例。当前代码直接将验证后的OrderedDict对象传入order.items.add(),而非合法的模型实例,导致类型错误。 - 模型设计不合理:业务上一个订单项仅属于一个订单,使用
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
相关产品推荐
相关产品推荐

