Search code examples
djangodatetimedjango-rest-frameworkpython-datetimedjango-serializer

Remove Z from DateTimeField in serializer


Is there a way to make my serializer print the datetimefield by default like this

 2022-03-28T00:00:00+00:00

Instead of this

 2022-03-23T03:16:00Z 

I get the first output when I do this

return obj.time.isoformat()

Solution

  • Cause

    If you look into the code of django-rest-framework in serializers.DateTimeField if datetime is UTC timezone, the UTC offset (+00:00) will get converted to Z as can be seen here

    Solution

    If you want to make it reusable for DateTimeField, you need to create a custom serializer DateTimeField that inherits from serializers.DateTimeField and override the to_representation method by coping codes from django-rest-framework and removing lines that convert UTC offset string to Z.

    from restframework import ISO_8601
    from restframework import serializers
    
    
    class CustomDateTimeField(serializers.DateTimeField):
    
        def to_representation(self, value):
            if not value:
                return None
    
            output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT)
    
            if output_format is None or isinstance(value, str):
                return value
    
            value = self.enforce_timezone(value)
    
            if output_format.lower() == ISO_8601:
                value = value.isoformat()
                # remove lines that convert "+00:00" to "Z"
                # See https://github.com/encode/django-rest-framework/blob/f4cf0260bf3c9323e798325702be690ca25949ca/rest_framework/fields.py#L1239:L1240
                return value
            return value.strftime(output_format)
    

    Then use this in your serializer instead of serializers.DateTimeField

    class MySerializer(serializers.Serializer):
        datetime = CustomDateTimeField()
    

    Extra

    If you want to use it in serializers.ModelSerializer, you need to follow below steps

    1. Create a custom ModelSerializer that inherits from serializers.ModelSerializer and set serializer_field_mapping attribute as follows
    class CustomModelSerializer(serializers.ModelSerializer):
        serializer_field_mapping = {
            # copy serializer_field_mapping
            **serializers.ModelSerializer.serializer_field_mapping,
            # override models.DateTimeField to map to CustomDateTimeField
            models.DateTimeField: CustomDateTimeField,
        }
    
    1. Use CustomModelSerializer instead of serializers.ModelSerializer. E.g.
    class LogSerializer(CustomModelSerializer):
        class Meta:
            model = Log
            fields = ["id", "created_at"]