gpt4 book ai didi

django - 如何在不重复太多的情况下处理 django DRF 中的时区?

转载 作者:行者123 更新时间:2023-12-05 04:47:36 24 4
gpt4 key购买 nike

  • 简介:我的项目TIME_ZONE 等于'UTC' 而我的用户来自太多时区。因此,当我使用 datetimedateTime 进行 POSTPUT 时字段 我在 serializer.save() 之前将这些字段转换为 UTC。然后,当用户发出 GET 请求时,我将相同的字段转换回用户的时区,即 request.user.timezone
# simplified functions

def localize(usertimzone, date, type):
"""
type = 'date', 'time', 'datetime'
"""
from dateutil import parser
date = parser.parse(date)
if not date.tzinfo:
usertimzone = pytz.timezone(usertimzone)
date = usertimzone.localize(date)
utc_date = date.astimezone(pytz.utc)
return utc_date

def normalize(usertimzone, date, type):
current_user_tz = pytz.timezone(usertimzone)
date = current_user_tz.localize(date)
return date
#usages example
def post(self, request, *args, **kwargs):
alert_date = request.data.get('alert_date')
if alert_date:
request.data['alert_date'] = localize(request.user.timezone, alert_date, 'datetime')
  • 问题:我在太多 View 中使用了这些函数,每次创建新 View 时我都会再次使用它。
  • 目标:我需要找到一种方法在一个函数中实现这一点,该函数将所有dateFieldtimeFielddatetimeField 字段。
  • 我试过:创建一个类 View 并在其中使用这些函数,然后为每个新应用覆盖该类。但是,每个模型都有名称不同的日期字段,很难制定一个灵活的函数来识别哪些字段需要本地化或规范化。

注意:我的意思是通过标准化将时区从 UTC 转换为当前登录用户时区。

最佳答案

如 DRF 中 DateTimeFielddocumentation 中所述,它有一个参数 default_timezone:

default_timezone - A pytz.timezone representing the timezone. Ifnot specified and the USE_TZ setting is enabled, this defaults tothe currenttimezone.If USE_TZ is disabled, then datetime objects will be naive.

正如它还描述的那样,只要您设置了 USE_TZ,该字段就会自动使用当前时区。这当然意味着您必须以某种方式设置( activate [Django docs] )当前时区。 Django 的 documentation 也有一些示例代码使用 session 来存储时区和中间件来设置它,尽管看起来您将时区存储在用户对象本身中,因此您可以编写一个使用它的中间件。此外,由于您使用 DRF 进行身份验证,它实际上在 View 层进行身份验证,因此中间件实际上没有经过身份验证的用户,因为您使用的是 rest_framework_simplejwt 您可以使用 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

将此中间件添加到 settings.py 中的 MIDDLEWARE 列表中 AuthenticationMiddleware 之后的某处,理想情况下最后应该可以工作:

MIDDLEWARE = [
...
'path.to.TimezoneMiddleware',
]

虽然上面的解决方案一开始看起来不错,但后来就需要使用变通方法了。更好的方法是使用可以设置当前时区的混合。 ApiView 类的 initial 方法是我们 mixin 完成任务的一个好点,该方法在实际 View 方法 (getpost 等)被调用,因此它适合我们的需要:

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):
...

关于django - 如何在不重复太多的情况下处理 django DRF 中的时区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68418165/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com