如中所述文档 https://www.django-rest-framework.org/api-guide/fields/#datetimefield for DateTimeField
在DRF中,它有一个参数default_timezone
:
default_timezone
- A pytz.timezone
代表时区。如果
未指定且USE_TZ
设置已启用,默认为
这当前的
时区 https://docs.djangoproject.com/en/stable/topics/i18n/timezones/#default-time-zone-and-current-time-zone.
If USE_TZ
被禁用,那么日期时间对象将是幼稚的。
正如它也描述的那样,只要你设置了USE_TZ
该字段将自动使用当前时区。这当然意味着您必须设置(activate[Django 文档] https://docs.djangoproject.com/en/3.2/ref/utils/#django.utils.timezone.activate)以某种方式当前时区。姜戈的文档 https://docs.djangoproject.com/en/3.2/topics/i18n/timezones/#selecting-the-current-time-zone还有一些示例代码,使用会话来存储时区和中间件来设置它,尽管您似乎将时区存储在用户对象本身中,因此您可以编写一个使用它的中间件。另外,由于您使用 DRF 进行身份验证,它实际上在视图层上进行身份验证,因此中间件实际上并没有经过身份验证的用户,因为您正在使用rest_framework_simplejwt
您可以使用中描述的解决方法这个问题 https://stackoverflow.com/q/54945856/14991864:
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
将此中间件添加到MIDDLEWARE
列出在settings.py
之后的某个地方AuthenticationMiddleware
,理想情况下最后应该起作用:
MIDDLEWARE = [
...
'path.to.TimezoneMiddleware',
]
尽管上面的解决方案一开始看起来不错,但后来就需要使用解决方法。更好的方法是使用 mixin 来设置当前时区。我们的 mixin 完成任务的一个好点是initial
的方法ApiView
类,此方法在实际视图方法之前调用(get
, post
等)被调用,因此它适合我们的需要:
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):
...