Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-rest-framework timezone aware renderers/parsers

I'm building an app that would serve people located in different places arround the world.
I'm using Django-Rest-Framwork for the communication between the clients and the server.
All DateTime values are saved to the DB as UTC (I have USE_TZ = True and TIME_ZONE = 'Greenwich' in settings.py).

I will be getting from the user his/her local timezone.

To test DRF for timezone awareness I wrote this middleware with fixed timezone:

import pytz
from django.utils import timezone

class TimezoneMiddleware(object):
    def process_request(self, request):
        timezone.activate(pytz.timezone("Asia/Jerusalem"))

The problem is:
I have a case in which I'm getting from the user "start_time" and "end_time" fields containting datetimes in the user's LOCAL timezone which gets through the UnicodeJSONRenderer to a ModelSerializer and then saved to the DB. However, they are saved as if they were in UTC.

At this point I would expect the serializer (or parser) to treat the datetime input from the user as datetime that needs to be converted from "Asia/Jerusalem" to UTC before saving to the DB since I performed timezone.activate(pytz.timezone("Asia/Jerusalem")).

The same goes when the data is parsed back in the response through JSONParser.
While expecting DateTime fields in the returned JSON to be in the timezone activated in the middleware, they are returned as UTC.

How can I easily achieve that in DRF?

like image 622
OrPo Avatar asked Jun 26 '13 22:06

OrPo


2 Answers

I had the same problem and solved it by adding new type of field:

class DateTimeTzAwareField(serializers.DateTimeField):

    def to_native(self, value):
        value = timezone.localtime(value)
        return super(DateTimeTzAwareField, self).to_native(value)

and now you can use it in ModelSerializer:

class XSerializer(serializers.ModelSerializer):
    start = DateTimeTzAwareField()
    end = DateTimeTzAwareField()

    class Meta:
        model = XModel
        fields = (
             'id',
             'start',
             'end',
        )
like image 160
yakxxx Avatar answered Oct 16 '22 09:10

yakxxx


The answer by @yakxxx seems to be the best solution. I am posting it again after updating it to work with newer versions of restframework

inside my directory (common/serializers.py)

from rest_framework import serializers
from django.utils import timezone

class DateTimeFieldWihTZ(serializers.DateTimeField):

    def to_representation(self, value):
        value = timezone.localtime(value)
        return super(DateTimeFieldWihTZ, self).to_representation(value)

Inside my application

from common.serializers import DateTimeFieldWihTZ

class MyObjectSerializer(serializers.ModelSerializer):

    start = DateTimeFieldWihTZ(format='%d %b %Y %I:%M %p')
    end = DateTimeFieldWihTZ(format='%d %b %Y %I:%M %p')
like image 17
Ramast Avatar answered Oct 16 '22 09:10

Ramast