DjangoRestFramework ModelSerializer DateTimeField only conversion to current timezone when creating an object

Edit: now this is recognized as a bug and it looks like the fix is ​​being performed: https://github.com/tomchristie/django-rest-framework/issues/3732#issuecomment-267635612

I have a Django project where I expect the user to be in a specific time zone. I have TIME_ZONE = 'Asia/Kolkata' and USE_TZ = True in my settings.

I have a model that includes a datetimefield field. When I first create the object, modelerializer gives datetimes with a final +5:30 . Annoyingly, datetimes with auto_now_add=True give UTC datetimes with a finite Z I fixed this by setting a default field for the called one for the current time.

If I serialize the object again at any point, all dates are in UTC with a ending Z From the Django documentation, I would expect the serializer to use the current time zone, which by default corresponds to the default time zone set by TIME_ZONE = 'Asia/Kolkata' . I checked the current time zone in my view using get_current_timezone_name() and this is 'Asia/Kolkata' . I even tried using activate('Asia/Kolkata') in my opinion, but the time is still returning to UTC.

Please note that all times are correct (UTC time is 5:30 hours earlier), this is just what I expect the time to be converted. All dates are stored in the database as UTC, as expected.

Am I missing something or is it a bug with Django Rest Framework serializers?

+7
django datetime serialization django-rest-framework
source share
1 answer

Take a look at the documentation here: http://www.django-rest-framework.org/api-guide/fields/#datetimefield

Signature: DateTimeField (format = None, input_formats = None)

format - A string representing the output format. If not specified, this default value matches the value for the DATETIME_FORMAT parameter, which will be "iso-8601" if not set. Setting to a format string indicates that the return values ​​to_representation should be forced into the string output. Format strings are described below. Setting this value to None means Python datetime objects must be returned to_representation. In this case, the datetime encoding will be determined by the renderer.

When None is used for the datetime format, objects will be returned to_representation, and the final presentation of the output will be determined by the rendering class.

In the case of JSON, this means that the datetime representation uses the ECMA 262 timeline specification by default. This is a subset of ISO 8601 that uses millisecond precision and includes the suffix β€œZ” for the UTC time zone, for example: 2013-01-29T12: 34: 56.123Z .

So the UTC (Z) representation of your datetime object is actually the default behavior.

When you create or update a model instance through Djangorest, the serializer will be called using data kwarg, which does not happen if you use a list or a detailed view.

In both cases, your view will return serializer.data . In the case of the create / update operation, this will be the view of serializer.validated_data , while in the case of the list / detail operation it will be a direct view of the instance.

In both cases, the representation is achieved by calling field.to_representation with kwarg format=None by default, which forces the field to return the value of a simple string.

The magic happens here :

  • create / update : checking returns an object corresponding to the time zone that includes your standard time zone. It converts to a string by calling its isoformat() method and returns as is.
  • list / retrieve : ORM django saves the timestamp as UTC. It converts to a string by calling the isoformat() method , but DRF replaces +00:00 with Z (see link above).

So, to get the desired result with a timezone offset, you can pass format=None or the strftime custom string to DateTimeField in your serializer. However, you will always get UTC time from +00:00 , because this is what the data (fortunately) is stored as.

If you want the actual offset to be 'Asia/Kolkata' , you probably have to define your own DateTimeField :

 from django.utils import timezone class CustomDateTimeField(serializers.DateTimeField): def to_representation(self, value): tz = timezone.get_default_timezone() # timezone.localtime() defaults to the current tz, you only # need the `tz` arg if the current tz != default tz value = timezone.localtime(value, timezone=tz) # py3 notation below, for py2 do: # return super(CustomDateTimeField, self).to_representation(value) return super().to_representation(value) 
+7
source share

All Articles