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

Django REST Framework批量更新字典列表API报错求助

问题:批量更新Waitlist记录时收到400 Bad Request错误

错误详情

HTTP 400 Bad Request
Allow: PUT, OPTIONS
Content-Type: application/json
Vary: Accept

[
{
"non_field_errors": [
"Expected a list of items but got type "dict"."
]
},
{
"non_field_errors": [
"Expected a list of items but got type "dict"."
]
}
]

传入的JSON数据

[
    {
        "id": "1",
        "order": "5"
    },
    {
        "id": "2",
        "order": "3"
    }
]

相关代码

Waitlist模型

class Waitlist(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50, blank=True)
    identification = models.CharField(max_length=50)

    email = models.EmailField(max_length=100, validators=[], blank=True)
    mobile_phone = PhoneNumberField(blank=True)

    store_number = models.PositiveSmallIntegerField()
    order = models.PositiveSmallIntegerField()
    status = models.PositiveSmallIntegerField()

    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.first_name + ' ' + self.last_name

views.py核心代码

from django.shortcuts import render, get_object_or_404
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from .models import Waitlist
from .serializers import WaitlistOrderSerializer, WaitlistOrderListSerializer

@api_view(['PUT'])
def waitlistOrder(request):
    waitlist_data = request.data
    waitlist = []
    for data in waitlist_data:
        waitlist_id = data.get('id')
        w = Waitlist.objects.get(id=waitlist_id)
        waitlist.append(w)
    serializer = WaitlistOrderListSerializer(
        waitlist, data=waitlist_data, many=True)
    if serializer.is_valid():
        serializer.save()
        return Response({'success': 'Waitlist order updated successfully'})
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

serializers.py核心代码

class WaitlistOrderSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    order = serializers.IntegerField()

    def update(self, instance, validated_data):
        instance.order = validated_data.get('order', instance.order)
        instance.save()
        return instance

class WaitlistOrderListSerializer(serializers.ListSerializer):
    child = WaitlistOrderSerializer()

    def update(self, instances, validated_data):
        for instance, data in zip(instances, validated_data):
            self.child.update(instance, data)
        return instances

解决方案

错误核心原因是:你已经自定义了WaitlistOrderListSerializer作为列表序列化器,但在视图初始化序列化器时额外传递了many=True参数,导致DRF重复解析,把每个字典数据当成列表处理,从而抛出类型不匹配的错误。

1. 修复序列化器初始化代码

移除many=True参数:

serializer = WaitlistOrderListSerializer(waitlist, data=waitlist_data)

2. 优化实例查询逻辑

  • 改用get_object_or_404避免ID不存在时抛出未捕获的异常:
    w = get_object_or_404(Waitlist, id=waitlist_id)
    
  • 批量查询实例减少数据库请求次数,同时保证顺序匹配:
    waitlist_ids = [data.get('id') for data in waitlist_data]
    # 批量查询
    waitlist_queryset = Waitlist.objects.filter(id__in=waitlist_ids)
    # 按传入ID的顺序排序实例
    waitlist = sorted(waitlist_queryset, key=lambda x: waitlist_ids.index(str(x.id)))
    

3. 增加事务保证原子性

在列表序列化器的update方法中添加事务,确保批量更新操作要么全部成功,要么全部回滚:

from django.db import transaction

class WaitlistOrderListSerializer(serializers.ListSerializer):
    child = WaitlistOrderSerializer()

    @transaction.atomic
    def update(self, instances, validated_data):
        for instance, data in zip(instances, validated_data):
            self.child.update(instance, data)
        return instances

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:05:15