Pass None to DRF SerializerField's to_representation

2.3k Views Asked by At

I have the following SerializerField:

class TimestampField(Field):
    def to_representation(self, value):
        if not value:
            return ''

        return value.timestamp()

And I use it like this in my serializer:

class ArticlePhotobookSerializer(ModelSerializer):  
    delivery_date_from = TimestampField()
    delivery_date_to = TimestampField()

Now the getter delivery_date_to can return None, which I want to transform into an empty string using the to_representation method. however, when I use the Serializer to parse this None value, it doesn't even enter the to_representation method and immediately returns None. What should I change to also use the method to_representation for None?

2

There are 2 best solutions below

1
On BEST ANSWER

By default serializer's to_representation method skip fields with None value (see source).

You can write mixin class to override default to_representation:

class ToReprMixin(object):  
    def to_representation(self, instance):
        ret = OrderedDict()
        fields = [field for field in self.fields.values() if not field.write_only]

        for field in fields:
            try:
                attribute = field.get_attribute(instance)
            except SkipField:
                continue

            ret[field.field_name] = field.to_representation(attribute)

        return ret

and use it in your serializers:

class ArticlePhotobookSerializer(ToReprMixin, ModelSerializer):  
    ...
0
On

If you would like to change the result of to_representation when there is no instance (not exactly the same problem as you had, but matches the question title), to_representation will not even be called in DRF v3. One can change the result by subclassing the get_initial method:

    def get_initial(self):
        """
        Return a value to use when the field is being returned as a primitive
        value, without any object instance.
        """
        if callable(self.initial):
            return self.initial()
        return self.initial

Heres an example:

    def get_initial(self) -> dict:
        return {'display_name': 'moocows'}

Here we use the context as initial representation:

    def get_initial(self) -> dict:
        return self.context