Django Rest Framework - How to add custom field in ModelSerializer

PythonDjangoDjango Rest-Framework

Python Problem Overview


I created a ModelSerializer and want to add a custom field which is not part of my model.

I found a description to add extra fields here and I tried the following:

customField = CharField(source='my_field')

When I add this field and call my validate() function then this field is not part of the attr dict. attr contains all model fields specified except the extra fields. So I cannot access this field in my overwritten validation, can I?

When I add this field to the field list like this:

class Meta:
    model = Account
    fields = ('myfield1', 'myfield2', 'customField')

then I get an error because customField is not part of my model - what is correct because I want to add it just for this serializer.

Is there any way to add a custom field?

Python Solutions


Solution 1 - Python

In fact there a solution without touching at all the model. You can use SerializerMethodField which allow you to plug any method to your serializer.

class FooSerializer(ModelSerializer):
    foo = serializers.SerializerMethodField()

    def get_foo(self, obj):
        return "Foo id: %i" % obj.pk

Solution 2 - Python

You're doing the right thing, except that CharField (and the other typed fields) are for writable fields.

In this case you just want a simple read-only field, so instead just use:

customField = Field(source='get_absolute_url')

Solution 3 - Python

...for clarity, if you have a Model Method defined in the following way:

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

You can add the result of calling said method to your serializer like so:

class MyModelSerializer(serializers.ModelSerializer):
    model_method_field = serializers.CharField(source='model_method')

p.s. Since the custom field isn't really a field in your model, you'll usually want to make it read-only, like so:

class Meta:
    model = MyModel
    read_only_fields = (
        'model_method_field',
        )

Solution 4 - Python

here answer for your question. you should add to your model Account:

@property
def my_field(self):
    return None

now you can use:

customField = CharField(source='my_field')

source: https://stackoverflow.com/a/18396622/3220916

Solution 5 - Python

To show self.author.full_name, I got an error with Field. It worked with ReadOnlyField:

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    author_name = ReadOnlyField(source="author.full_name")
    class Meta:
        model = Comment
        fields = ('url', 'content', 'author_name', 'author')

Solution 6 - Python

After reading all the answers here my conclusion is that it is impossible to do this cleanly. You have to play dirty and do something hadkish like creating a write_only field and then override the validate and to_representation methods. This is what worked for me:

class FooSerializer(ModelSerializer):

    foo = CharField(write_only=True)

    class Meta:
        model = Foo
        fields = ["foo", ...]

    def validate(self, data):
        foo = data.pop("foo", None)
        # Do what you want with your value
        return super().validate(data)

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data["foo"] = whatever_you_want
        return data

Solution 7 - Python

With the last version of Django Rest Framework, you need to create a method in your model with the name of the field you want to add.

class Foo(models.Model):
    . . .
    def foo(self):
        return 'stuff'
    . . .
 
class FooSerializer(ModelSerializer):
    foo = serializers.ReadOnlyField()
    
    class Meta:
        model = Foo
        fields = ('foo',)

Solution 8 - Python

I was looking for a solution for adding a writable custom field to a model serializer. I found this one, which has not been covered in the answers to this question.

It seems like you do indeed need to write your own simple Serializer.

class PassThroughSerializer(serializers.Field):
    def to_representation(self, instance):
        # This function is for the direction: Instance -> Dict
        # If you only need this, use a ReadOnlyField, or SerializerField
        return None

    def to_internal_value(self, data):
        # This function is for the direction: Dict -> Instance
        # Here you can manipulate the data if you need to.
        return data

Now you can use this Serializer to add custom fields to a ModelSerializer

class MyModelSerializer(serializers.ModelSerializer)
    my_custom_field = PassThroughSerializer()

    def create(self, validated_data):
        # now the key 'my_custom_field' is available in validated_data
        ...
        return instance

This also works, if the Model MyModel actually has a property called my_custom_field but you want to ignore its validators.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRonView Question on Stackoverflow
Solution 1 - PythonIdahoView Answer on Stackoverflow
Solution 2 - PythonTom ChristieView Answer on Stackoverflow
Solution 3 - PythonLindausonView Answer on Stackoverflow
Solution 4 - Pythonva-devView Answer on Stackoverflow
Solution 5 - PythonFrançois ConstantView Answer on Stackoverflow
Solution 6 - PythonArielView Answer on Stackoverflow
Solution 7 - PythonGuillaume VincentView Answer on Stackoverflow
Solution 8 - PythonDavid SchumannView Answer on Stackoverflow