Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework: get_FOO_display in serializer not letting me POST

I recently added a source='get_fieldname_display to my serializer. It worked perfectly for the purpose of obtaining the display value of a choices tuple but now I can no longer POST data using the API end point without getting an error:

TypeError: 'get_fieldname_display' is an invalid keyword argument for this function

To be clear, the addition to the serializer was this line specifically:

fieldName = serializers.CharField(source='fieldName_display')

I know that this line is causing the problem because when I comment it out, I can POST data without a problem. However, I need this line in there so I may obtain the display names from the choices tuple when I am GETting data.

I think the problem may be remedied if I use two different serializers, one for GET and another for POST, but I am not sure how to go about doing this--I am using a generics.ListCreateAPIView in my views.py.

EDIT:

My model looks like this:

class MakeObjects(models.Model):

    FIELD_NAME_CHOICES = (
        ("01", "Choice 1"), 
        ("02", "Choice 2"), 
    )

    fieldname = CharField(choices = FIELD_NAME_CHOICES)

My serializer looks like this:

class ObjectSerializer(serializers.ModelSerializer): 
       fieldname = serializers.CharField(source='get_fieldname_display')
       class Meta:
           model = MakeObjects
           fields = ('__all__')
like image 936
user8951490 Avatar asked Nov 15 '25 15:11

user8951490


1 Answers

To achieve that, you need custom serializer field.

Here's the snippet for python 3:

class DisplayNameWritableField(serializers.ChoiceField):
    def __init__(self, **kwargs):
        self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
        self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)

        self.allow_blank = kwargs.pop('allow_blank', False)
        super(ChoiceField, self).__init__(**kwargs)

    def to_representation(self, value):
        return self.choices.get(value, value)

    def bind(self, field_name, parent):
        super().bind(field_name, parent)
        self.choices = parent.Meta.model._meta.get_field(field_name).choices

Then:

class YourModelSerializer(serializers.ModelSerializer):
    your_choiced_model_field = DisplayNameWritableField()

This is a bit hacky though, so not all auto-docs engines detect choices correctly, even though this works pretty well.

You might also like https://github.com/encode/django-rest-framework/issues/1755

like image 75
LinPy fan Avatar answered Nov 18 '25 04:11

LinPy fan