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

如何通过__init__或__new__方法在Django DRF序列化器中动态设置ChoiceField选项?

问题修复:Django序列化器动态设置ChoiceField选项

错误原因分析

  1. 初始化方法传参错误:原代码中super().__init__(self, *args, **kwargs)多传了self,导致序列化器把自身当作要序列化的instance,访问serializer.data时会尝试从序列化器实例本身获取name属性,从而抛出AttributeError。
  2. 类级别字段修改风险:修改_declared_fields会影响所有CatSerializer实例,存在线程安全问题,应该操作实例级别的self.fields。
  3. 冗余的请求体解析:DRF的request.data已经自动解析了请求体,无需手动调用json.loads(request.body)。

修复后的代码

serializers.py

from rest_framework import serializers

class CatSerializer(serializers.Serializer):
    name = serializers.ChoiceField(choices=[])

    def __init__(self, *args, **kwargs):
        # 取出动态传入的选项参数
        name_choices = kwargs.pop("names", [])
        # 正确调用父类初始化方法
        super().__init__(*args, **kwargs)
        # 为当前实例的name字段设置动态选项
        if name_choices:
            self.fields['name'].choices = name_choices

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import CatSerializer

class CatView(APIView):
    def __init__(self, *arg, **kwargs):
        super().__init__(*arg, **kwargs)
        self.names = ['a', 'b', 'c']

    def get_serializer(self, *args, **kwargs):
        return CatSerializer(*args, **kwargs, names=self.names)

    def post(self, request):
        # 直接使用DRF解析后的request.data
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            return Response({
                "message": "success",
                "serialized-data": serializer.data
            })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

核心改进点

  • 移除__new__方法,在__init__中处理动态选项,保证每个序列化器实例的独立性。
  • 操作实例级别的self.fields,避免类级别字段修改带来的并发问题。
  • 修正父类初始化方法的传参错误,使用DRF原生的request.data简化代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 20:10:25