Django REST Framework订单API POST请求TypeError报错排查
报错信息
调用Django REST Framework订单POST接口时触发如下错误:
product = Product.objects.get(id=i['product']) TypeError: string indices must be integers
当前错误请求体
Postman中当前使用的请求JSON如下:
{ "orderItems":{ "product": {"name":"abc", "brand":"def", "image":"www.example.com/img", "description":"xyz", "price":"50"}, "qty":"2", "price":"200" }, "shippingAddress": { "address":"abc", "city":"B", "postalCode":"12345", }, "paymentMethod":"monify", "itemPrice":"100" }
项目相关代码
模型定义(models.py)
class Product(models.Model): category = models.CharField(max_length=50, choices=Categories.choices, default=Categories.medications) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_product", null=True) name = models.CharField(max_length=150) brand = models.CharField(max_length=255, default="brand") productClass = models.CharField(max_length=50, null=True, blank=True) image = models.ImageField(upload_to="images/products/") label = models.CharField(max_length=254, default='', blank=True, null=True) price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True) stock = models.IntegerField(null=True, blank=True, default=0) dateCreated = models.DateTimeField(auto_now_add=True) class Order(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_order", null=True) paymentMethod = models.CharField(max_length=200, null=True, blank=True) dateCreated = models.DateTimeField(auto_now_add=True) def __str__(self): return str(self.dateCreated) class OrderItem(models.Model): product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True) image = models.CharField(max_length=200, null=True, blank=True) order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True) name = models.CharField(max_length=200, null=True, blank=True) qty = models.IntegerField(null=True, blank=True, default=0) price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True) def __str__(self): return str(self.name)
接口视图代码
def addOrderItems(request): user = request.user data = request.data orderItems = data['orderItems'] if orderItems and len(orderItems) == 0: return Response({'detail': 'Order item was not provided'}, status=status.HTTP_400_BAD_REQUEST) else: # Step 1: 创建订单主记录 order = Order.objects.create( user=user, paymentMethod=data['paymentMethod'], ) #Step 2: 创建收货地址 shipping = ShippingAddress.objects.create( order=order, address=data['shippingAddress']['address'], ) # Step 3: 创建订单项,绑定订单关联关系 for i in orderItems: product = Product.objects.get(id=i['product']) item = OrderItem.objects.create( product=product, order=order, name=product.name, qty=i['qty'], price=i['price'], image=product.image.url, ) # Step 4: 扣减商品库存 product.countInStock -= item.qty product.save() serializer = OrderSerializer(order, many=False) return Response(serializer.data)
问题原因
- 直接触发报错的原因:
orderItems字段传了单个JSON对象,但视图代码用for i in orderItems遍历该字段,遍历对象时拿到的i是对象的键名(字符串类型,比如"product"、"qty"),此时执行i['product']相当于用字符串做键去索引字符串,和报错提示的string indices must be integers完全匹配。 - 请求结构不符合后端预期:视图中查询商品的逻辑是
Product.objects.get(id=i['product']),说明每个订单项里的product字段需要传数据库中已存在商品的整数ID,不需要传完整的商品详情对象,商品的名称、图片、价格等字段后端会自行根据ID查询数据库获取。 - 额外代码bug:Product模型中库存字段名是
stock,视图扣库存时写的是countInStock,修复请求体问题后这里会触发属性不存在的错误,需要同步修正。 - JSON格式小问题:当前请求体中
shippingAddress的最后一个字段末尾多了冗余逗号,部分严格JSON解析场景下会报格式错误;数字类型字段(qty、price、itemPrice)不需要加引号传字符串,直接传数字类型即可。
修复方案
- 调整请求体结构:把
orderItems改为数组格式,哪怕只买1件商品也要放在数组中;每个订单项的product字段替换为实际存在的商品ID,删除冗余的商品详情字段;去掉JSON里的冗余逗号,数字类型字段直接传数值。合法请求示例:
{ "orderItems": [ { "product": 1, "qty": 2, "price": 200 } ], "shippingAddress": { "address": "abc", "city": "B", "postalCode": "12345" }, "paymentMethod": "monify", "itemPrice": 100 }
注意:示例中
product对应的1要替换为你数据库中实际存在的Product记录主键ID,一次下单多件商品时在orderItems数组里追加多个订单项对象即可。
- 修复视图代码的库存字段笔误:将
product.countInStock -= item.qty改为product.stock -= item.qty。 - 补全收货地址创建逻辑:当前创建ShippingAddress时只传了address字段,建议把city、postalCode等传入的字段同步写入,避免收货地址数据丢失。
内容的提问来源于stack exchange,提问作者C-Bizz
相关产品推荐
相关产品推荐

