Django Rest Framework with ChoiceField
Django provides the Model.get_FOO_display
method to get the "human-readable" value of a field:
class UserSerializer(serializers.ModelSerializer): gender = serializers.SerializerMethodField() class Meta: model = User def get_gender(self,obj): return obj.get_gender_display()
for the latest DRF (3.6.3) - easiest method is:
gender = serializers.CharField(source='get_gender_display')
I suggest to use django-models-utils with a custom DRF serializer field
Code becomes:
# models.pyfrom model_utils import Choicesclass User(AbstractUser): GENDER = Choices( ('M', 'Male'), ('F', 'Female'), ) gender = models.CharField(max_length=1, choices=GENDER, default=GENDER.M)# serializers.py from rest_framework import serializersclass ChoicesField(serializers.Field): def __init__(self, choices, **kwargs): self._choices = choices super(ChoicesField, self).__init__(**kwargs) def to_representation(self, obj): return self._choices[obj] def to_internal_value(self, data): return getattr(self._choices, data)class UserSerializer(serializers.ModelSerializer): gender = ChoicesField(choices=User.GENDER) class Meta: model = User# viewsets.pyclass UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer
An update for this thread, in the latest versions of DRF there is actually a ChoiceField.
So all you need to do if you want to return the display_name
is to subclass ChoiceField
to_representation
method like this:
from django.contrib.auth import get_user_modelfrom rest_framework import serializersUser = get_user_model()class ChoiceField(serializers.ChoiceField): def to_representation(self, obj): if obj == '' and self.allow_blank: return obj return self._choices[obj] def to_internal_value(self, data): # To support inserts with the value if data == '' and self.allow_blank: return '' for key, val in self._choices.items(): if val == data: return key self.fail('invalid_choice', input=data)class UserSerializer(serializers.ModelSerializer): gender = ChoiceField(choices=User.GENDER_CHOICES) class Meta: model = User
So there is no need to change the __init__
method or add any additional package.