5👍
As described in the documentation for DateTimeField
in DRF, it has an argument default_timezone
:
default_timezone
– Apytz.timezone
representing the timezone. If
not specified and theUSE_TZ
setting is enabled, this defaults to
the current
timezone.
IfUSE_TZ
is disabled, then datetime objects will be naive.
As it also describes as long as you have set USE_TZ
the field will automatically use the current timezone. This of course means you would have to set (activate
[Django docs]) the current timezone somehow. Django’s documentation also has some sample code that uses sessions for storing the timezone and a middleware to set it, although it seems you store the timezone in the user object itself so you can write a middleware that uses that instead. Also since you use DRF for authentication, it actually does the authentication on the view layer, so the middleware does not really have the authenticated user, Since you are using rest_framework_simplejwt
you can use the workaround described in this question:
import pytz
from django.utils import timezone
from rest_framework_simplejwt import authentication
class TimezoneMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
tzname = None
user = self.get_request_user(request)
if user:
tzname = user.timezone
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.deactivate()
return self.get_response(request)
def get_request_user(self, request):
try:
return authentication.JWTAuthentication().authenticate(request)[0]
except:
return None
Add this middleware to the MIDDLEWARE
list in settings.py
somewhere after AuthenticationMiddleware
, ideally at the last should work:
MIDDLEWARE = [
...
'path.to.TimezoneMiddleware',
]
Although the above solution seemed good at the start, it later turned to needing to use a workaround. A better way would be to use a mixin that would set the current timezone. A good point for our mixin to do it’s task would be the initial
method of the ApiView
class, this method is called just before the actual view method (get
, post
, etc.) is called so it suits our needs:
import pytz
from django.utils import timezone
class TimezoneMixin:
def initial(self, request, *args, **kwargs):
super().initial(request, *args, **kwargs)
tzname = None
if request.user.is_authenticated:
tzname = request.user.timezone
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.deactivate()
class YourView(TimezoneMixin, SomeViewClassFromDRF):
...