How to pass choice display name to model serialize in Django REST framework?

Question:

My env is Django 2.0.3, DRF 3.8.2 and Python 3.6.4.

I have a model in serializers.py:

class TransferCostSerializer(serializers.ModelSerializer):

    def to_representation(self, instance):
        field_view = super().to_representation(instance)
        if field_view['is_active']:
            return field_view
        return None

    class Meta:
        model = TransferCost
        fields = ('id', 'destination', 'total_cost', 'is_active',)

Where destination field is choice field of 3 elements:

DESTINATION = (
    ('none', _('I will drive by myself')),
    ('transfer_airport', _('Only from airport')),
    ('transfer_round_trip', _('Round trip')),
)

This is my models.py:

class TransferCost(models.Model):

    destination = models.CharField(
        _('Transfer Destination'), choices=DESTINATION, max_length=55
    )
    total_cost = models.PositiveIntegerField(
        _('Total cost'), default=0
    )
    is_active = models.BooleanField(_('Transfer active?'), default=True)

    class Meta:
        verbose_name = _('Transfer')
        verbose_name_plural = _('Transfers')

    def __str__(self):
        return _('Transfer {}').format(self.destination)

..And I return JSON like this:

[
    {
        id: 1,
        destination: "transfer_airport",
        total_cost: 25,
        is_active: true
    },
    {
        id: 2,
        destination: "transfer_round_trip",
        total_cost: 45,
        is_active: true
    }
]

How to return destination field with his display name? For example:

[
    {
        id: 1,
        destination_display: "Only from airport",
        destination: "transfer_round_trip",
        total_cost: 25,
        is_active: true
    },
    {
        id: 2,
        destination_display: "Round trip",
        destination: "transfer_round_trip",
        total_cost: 45,
        is_active: true
    }
]

Would be great to have something like get_FOO_display() in serializers.py, but it’s not working. I need this thing, because I render form dynamically via Vue.js (as v-for select list).

Asked By: koddr

||

Answers:

you can use fields source with get_FOO_display

class TransferCostSerializer(serializers.ModelSerializer):
    destination_display = serializers.CharField(
        source='get_destination_display'
    )
Answered By: Brown Bear

just place get_destination_display withoput () in fields. like this:

class TransferCostSerializer(serializers.ModelSerializer):
    class Meta:
        model = TransferCost
        fields = ('id', 'get_destination_display', 'total_cost', 'is_active',)
Answered By: hadi ahadi

In case you want to have the values of all model fields with choices to be returned as display values, following worked out for me:


from rest_framework import serializers
from django.core.exceptions import FieldDoesNotExist

class TransferCostSerializer(serializers.ModelSerializer):
    class Meta:
        model = TransferCost
        fields = ('id', 'destination', 'total_cost', 'is_active',)

    def to_representation(self, instance):
        """
        Overwrites choices fields to return their display value instead of their value.
        """
        data = super().to_representation(instance)
        for field in data:
            try:
                if instance._meta.get_field(field).choices:        
                    data[field] = getattr(instance, "get_" + field + "_display")()
            except FieldDoesNotExist:
                pass
        return data

The other solutions dropped auto generated meta-information of the model fields, e.g., translated labels.

Answered By: sir_dance_a_lot