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

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)不需要加引号传字符串,直接传数字类型即可。
修复方案
  1. 调整请求体结构:把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数组里追加多个订单项对象即可。

  1. 修复视图代码的库存字段笔误:将product.countInStock -= item.qty改为product.stock -= item.qty。
  2. 补全收货地址创建逻辑:当前创建ShippingAddress时只传了address字段,建议把city、postalCode等传入的字段同步写入,避免收货地址数据丢失。

内容的提问来源于stack exchange,提问作者C-Bizz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:57:17