Django / Serializer - How to pass label attached to choice field in API?
I am trying to get the label attached to the relevant interger for the choice field. Although the API returns the interger, I cannot seem to be able to return the actual label value.
This is the current return:
[
{
"id": 16,
"frequency": 0,
},
{
"id": 15,
"frequency": 2,
}
]
What am I missing?
models
FREQUENCIES=(
(0,'Monthly'),
(1,'Weekly'),
(2,'Daily'),
(3, 'Bi-Weekly'),
)
class Model(models.Model):
frequency = models.IntegerField(choices=FREQUENCIES, default=0,null=True, blank=True)
serializer
class ModelSerializer(serializers.ModelSerializer):
frequency_label = serializers.ChoiceField(
choices=FREQUENCIES,
source='frequency',
read_only=True
)
class Meta:
model = Model
fields = [
'frequency',
'frequency_label',
]
viewset
class ModelViewSet(viewsets.ViewSet):
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
method='get',
responses={200: ModelSerializer(many=True)}
)
@action(detail=False, methods=['get'], url_path='list-rules')
def a(self, request):
q = Model.objects.filter(field=some_variable)
return Response(
ModelSerializer(q, many=True).data,
status=status.HTTP_200_OK
)
Short Answer:
Change your structure like this:
class ModelSerializer(serializers.ModelSerializer):
frequency_label = serializers.SerializerMethodField()
class Meta:
model = Model
fields = [
'frequency',
'frequency_label',
]
def get_frequency_label(self, obj):
return obj.get_frequency_display()
And it will work! :)
Complete Description:
part 1:
When you are using tuples like
WeekdayChoices = (
(1, 'Sunday'),
(2, 'Monday'),
...
)
Or IntegerChoices like
class WeekdayChoices(models.IntegerChoices):
SUNDAY = 1, 'Sunday'
MONDAY = 2, 'Monday'
...
Or TextChoices like
class WeekdayChoices(models.TextChoices):
SUNDAY = "Sunday", "یکشنبه"
MONDAY = "Monday", "دوشنبه"
...
Or other structures which contain two parts, django gives you a built-in method to call them to show the label to you. This methods structure is like get_fieldname_display which in your case it turned to get_frequency_display.
part 2:
To define a customized field in your serializer, you can use SerializerMethodField. To tell rest_framework how to compute that field, you should write a method for it. If your field name is foo, the default method name should be get_foo. For example you can add a field named welcome to your serializer like this:
class ModelSerializer(serializers.ModelSerializer):
frequency_label = serializers.SerializerMethodField()
welcome = serializers.SerializerMethodField()
class Meta:
model = Model
fields = [
'frequency',
'frequency_label',
'welcome',
]
def get_frequency_label(self, obj):
return obj.get_frequency_display()
def get_welcome(self, obj):
return "welcome :)"