GET API 返回选项的字符串而不是IDDjango 中常常要用到选项字段为了提高数据库效率和用户可读性,我们实际存储的是整数,显示的时候以字符串显示。这个属性在 Django Admin 得到了很好的处理,但到了 Django Rest Framework 就不会自动转化了。下面的在GET的时候显示字符串,但这个字段就变成只读但了。# models.pyclass User(AbstractUser): GENDER_CHOICES = ( (‘M’, ‘Male’), (‘F’, ‘Female’), ) gender = models.CharField(max_length=1, choices=GENDER_CHOICES)# serializers.py class UserSerializer(serializers.ModelSerializer): # 自定义了gender 字段,该字段变成只读的了。 gender = serializers.CharField(source=‘get_gender_display’) class Meta: model = User# viewsets.pyclass UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer这里涉及到一个有趣的实例方法: get_FOO_display 对于模型中含有 ++choices++ 参数的字段, FOO 是字段的名字, get_FOO_display() 返回选项的可读字符串要实现 model 中的 Choice Field, 在 GET 的时候显示选项名字,在POST的时候既能字符串又能接受ID方法一比如模型中有个status# models.pyclass CommonInfo(models.Model): INACTIVE = 0 PUBLISHED = 1 PENDING = -1 DRAFT = -2 REPORTED = -3 DELETED = -4 STATUS_CHOICES = ( (INACTIVE, ‘INACTIVE’), (PUBLISHED, ‘PUBLISHED’), (PENDING, ‘PENDING’), (DRAFT, ‘DRAFT’), (REPORTED, ‘REPORTED’), (DELETED, ‘DELETED’), ) status = models.SmallIntegerField( choices=STATUS_CHOICES, default=PUBLISHED)# utils.pyfrom rest_framework import serializersfrom collections import OrderedDictclass ChoiceDisplayField(serializers.Field): “““Custom ChoiceField serializer field.””” def init(self, choices, **kwargs): “““init.””” self._choices = OrderedDict(choices) super(ChoiceDisplayField, self).init(**kwargs) # 返回可读性良好的字符串而不是 1,-1 这样的数字 def to_representation(self, obj): “““Used while retrieving value for the field.””” return self._choices[obj] def to_internal_value(self, data): “““Used while storing value for the field.””” for i in self._choices: # 这样无论用户POST上来但是CHOICES的 Key 还是Value 都能被接受 if i == data or self._choices[i] == data: return i raise serializers.ValidationError(“Acceptable values are {0}.".format(list(self._choices.values())))# serializers.pyfrom utils import ChoiceDisplayFieldclass CommonInfoSerializer(serializers.ModelSerializer): INACTIVE = 0 PUBLISHED = 1 PENDING = -1 DRAFT = -2 REPORTED = -3 DELETED = -4 STATUS_CHOICES = ( (INACTIVE, ‘INACTIVE’), (PUBLISHED, ‘PUBLISHED’), (PENDING, ‘PENDING’), (DRAFT, ‘DRAFT’), (REPORTED, ‘REPORTED’), (DELETED, ‘DELETED’), ) status = ChoiceDisplayField(choices=STATUS_CHOICES)方法二参考页面提到了更简单的方法,虽然我没有试过。即:继承 ChoiceField 而不是 Field,就样就不用写 to_internal_value() 了。但 POST 只能接受 ID, 不能接受字符串,如下from rest_framework import serializersfrom collections import OrderedDictclass ChoiceDisplayField(serializers.ChoiceField): “““Custom ChoiceField serializer field.””” def init(self, choices, **kwargs): “““init.””” self._choices = OrderedDict(choices) super(ChoiceDisplayField, self).init(**kwargs) # 返回可读性良好的字符串而不是 1,-1 这样的数字 def to_representation(self, obj): “““Used while retrieving value for the field.””” return self._choices[obj]参考