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

DRF序列化器返回列表报错,批量创建Withdraw记录的问题解决

解决DRF ListCreateAPIView创建多条提现记录的序列化器错误

错误原因

你的WithdrawCreateSerializer的create方法返回了实例列表,但DRF默认的CreateModelMixin.create逻辑会把序列化器返回的对象当成单个实例,用原序列化器去序列化这个列表——而列表没有amount属性,因此触发AttributeError。


解决方案

方案一:重写视图的create方法,适配批量序列化返回

直接修改视图逻辑,让它处理序列化器返回的实例列表,并使用many=True参数完成批量序列化:

from rest_framework import generics
from rest_framework.response import Response
from rest_framework import status
from django.db import transaction

class WithdrawListCreateAPIView(generics.ListCreateAPIView):
    queryset = Withdraw.objects.all()
    serializer_class = WithdrawCreateSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        
        # 用事务保证多条记录要么全创建成功,要么全失败
        with transaction.atomic():
            instances = serializer.save()
        
        # 用many=True让序列化器处理实例列表
        response_serializer = self.get_serializer(instances, many=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(response_serializer.data)
        
        return Response(
            response_serializer.data,
            status=status.HTTP_201_CREATED,
            headers=headers
        )

方案二:拆分逻辑到视图,让序列化器只处理单条记录

如果希望序列化器保持单实例处理的职责,可以把金额拆分逻辑移到视图中:

# 序列化器(仅处理单条提现记录)
class WithdrawCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Withdraw
        fields = ['amount', 'user', 'account']  # 替换为你的实际字段

    def create(self, validated_data):
        return Withdraw.objects.create(**validated_data)

# 视图处理拆分逻辑
from rest_framework import generics
from rest_framework.response import Response
from rest_framework import status
from django.db import transaction

class WithdrawListCreateAPIView(generics.ListCreateAPIView):
    queryset = Withdraw.objects.all()
    serializer_class = WithdrawCreateSerializer

    def create(self, request, *args, **kwargs):
        total_amount = request.data.get('amount')
        max_amount = SETTLEMENT_MAX_AMOUNT
        instances = []
        
        with transaction.atomic():
            while total_amount > 0:
                current_amount = min(total_amount, max_amount)
                # 复制原请求数据,替换金额为当前拆分值
                data = request.data.copy()
                data['amount'] = current_amount
                
                serializer = self.get_serializer(data=data)
                serializer.is_valid(raise_exception=True)
                instances.append(serializer.save())
                
                total_amount -= current_amount
        
        response_serializer = self.get_serializer(instances, many=True)
        headers = self.get_success_headers(response_serializer.data[0])
        
        return Response(
            response_serializer.data,
            status=status.HTTP_201_CREATED,
            headers=headers
        )

注意事项

  • 两种方案都建议用transaction.atomic()包裹创建逻辑,避免出现部分记录创建成功的异常情况。
  • 确保请求中的其他关联字段(如用户、账户)能正确传递到每条拆分的提现记录中。
  • 如果使用方案一,要保证序列化器的create方法稳定返回实例列表,且验证逻辑覆盖批量创建的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:57:15