如何通过__init__或__new__方法在Django DRF序列化器中动态设置ChoiceField选项?
问题修复:Django序列化器动态设置ChoiceField选项
错误原因分析
- 初始化方法传参错误:原代码中
super().__init__(self, *args, **kwargs)多传了self,导致序列化器把自身当作要序列化的instance,访问serializer.data时会尝试从序列化器实例本身获取name属性,从而抛出AttributeError。 - 类级别字段修改风险:修改
_declared_fields会影响所有CatSerializer实例,存在线程安全问题,应该操作实例级别的self.fields。 - 冗余的请求体解析: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
相关产品推荐
相关产品推荐

