我有一个模型,其中存储了一个时区日期时间对象。我从网站上向我的一个视图打了一个Ajax电话,它进行了以下呼叫:
def uploads(request):
user = User.objects.get(username=request.user.get_username())
cases = Case.objects.filter(user_id=user.pk).order_by('-uploaded_on')[:5]
return JsonResponse(serializers.serialize('json', cases, fields=('col1', 'col2', 'col3', 'uploaded_on')), safe=False)
当在前端接收到JSON响应时,会使用JS对其进行解析和分析。我想在这里做的是用用户的时区修改"uploaded_on"列(我已经可以用user.timezone访问它,目前显示为字符串,例如"Germany/Berlin",但可以用pytz包轻松地将其转换为必要的对象(。
当我尝试像下面这样迭代QuerySet时,在前端接收到的值不会改变:
for case in cases:
case.uploaded_on.astimezone(pytz.timezone(user.timezone))
这可能与QuerySet是惰性的这一事实有关,就像Django文档中描述的那样。有人能建议如何做到这一点吗?
还有一个额外的问题:使用Django的序列化程序,我可以在一个JSON响应中传递多个QuerySet吗?当我试图在列表中打包一些时,我会得到一个MultiValueDictKeyError:
return JsonResponse(serializers.serialize('json', [cases, cases2]), safe=False)
对我来说,有两种方法:
-
用一个新列(类似于
uploaded_at_utz
(注释cases
查询集,并在数据库级别进行时区操作。例如,您可以使用TruncSecond
函数来执行以下操作:cases = Case.objects.filter(user_id=user.pk).annotate(uploaded_at_utz=TruncSecond('uploaded_on', tzinfo=pytz.timezone(user.timezone)).order_by('-uploaded_on')[:5]
-
另一种方法是在python级别执行此操作。为此,我会选择生成器函数,类似于:
def convert_to_timezone(cases, tzinfo): for case in cases: case.uploaded_on = case.uploaded_on.astimezone(tzinfo) yield case
然后,在中将convert_to_timezone(cases, pytz.timezone(user.timezone))
传递给JsonResponse
构造函数。
您还应该探索timezone.override和/或timezone.localtime的使用,尽管我不熟悉它们。
关于日期操作,datetime.astimezone()
返回一个新的日期时间,而不是就地转换。您需要将转换后的值分配回case.uploaded_on
。
for case in cases:
case.uploaded_on = case.uploaded_on.astimezone(pytz.timezone(user.timezone))
关于是否可以在单个JSON响应中传递多个查询集,可以使用itertools.chain
来实现这一点。
from itertools import chain
return JsonResponse(serializers.serialize('json', chain(cases, cases2)), safe=False)