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 :)"

more about SerializerMethodField

Вернуться на верх