简体   繁体   English

转换为本地时间 django 查询集

[英]Convert to Localtime django queryset

I have this following model definition in my models.py我的models.py中有以下 model 定义

from django.db import models
class Blog(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

in my settings.py I have在我的settings.py我有

TIME_ZONE = 'UTC'
USE_TZ = True

I want to get the times in specific timezone.我想获得特定时区的时间。 right now if I call Blog.objects.all() it's giving all the times in UTC format.现在,如果我调用Blog.objects.all() ,它会以UTC格式提供所有时间。 But I want the times in user timezone who requested.但我想要请求的用户时区中的时间。

I know there are filters and tags available on this.我知道这上面有过滤器和标签。 But as I am doing rest_framework I think I need to be able to do in Queryset .但是当我在做rest_framework时,我想我需要能够在Queryset中做。

Any help?有什么帮助吗?

Edit:编辑:

I have written the queryset like this so far到目前为止,我已经编写了这样的查询集

from django.utils import timezone
from django.db import models
Blog.objects.annotate(
    local_create_time = timezone.template_localtime(models.Expressionwrapper(models.F('created'), output_field=models.DateTimeField(), pytz.timezone('Europe/Madrid'))
)

It's not converting the data to Europe/Madrid timzone.它没有将数据转换为Europe/Madrid时区。 but outputting data into the UTC timzone.但将数据输出到UTC区。

So I checked the timzone.template_localtime(value, use_tz=None) definition.所以我检查了timzone.template_localtime(value, use_tz=None)定义。

For me use_tz is passing a tzinfo object but value is ExpressionWrapper(F(created))对我来说,use_tz 传递的是tzinfo object,但value ExpressionWrapper(F(created))

In python you can get the time in different timezones this way: 在python中,您可以通过以下方式获取不同时区的时间:

from datetime import datetime
from pytz import timezone

time_Madrid=datetime.now(timezone('Europe/Madrid'))
time_UTC=datetime.now(timezone('UTC'))
time_GMT=datetime.now(timezone('Etc/GMT-3'))

A very old question.一个很老的问题。 But I landed here with a similar problem.但是我在这里遇到了类似的问题。 And while the solution I have may not apply to your use case, it might.虽然我的解决方案可能不适用于您的用例,但它可能适用。 Your needs aren't 100% clear in the question.您的需求在问题中并非 100% 明确。

In my case as I have a website that anyone anywhere can use (as in a website, as that is true of them all) and further that local people can use to manage local events (so in local time) I had also to grapple with timezones in Django.就我而言,因为我有一个任何人都可以在任何地方使用的网站(就像在网站上一样,所有人都是如此)而且当地人可以用来管理当地事件(所以在当地时间)我还必须努力解决Django 中的时区。

Now I use Postgresql as a backend and my interests therefore apply to that context.现在我使用 Postgresql 作为后端,因此我的兴趣适用于该上下文。 And Postgresql basically stores all datetimes at UTC. Postgresql 基本上以 UTC 存储所有日期时间。 That is when I have a local time in the Python code and ask set a Django model field to that then on saving it the timezone information is only used for a conversion to UTC and then lost.那是当我在 Python 代码中有一个本地时间并要求设置一个 Django model 字段然后保存时区信息仅用于转换为 UTC 然后丢失。

When I then read that field using Django it is in UTC and I can localize it to a timezone, but what timezone?当我使用 Django 读取该字段时,它是 UTC,我可以将它本地化到一个时区,但是什么时区? There is the active time zone in Django and that is nice but there are in fact three timezones that are candidates for any context: Django 中有一个活动时区,这很好,但实际上有三个时区可用于任何上下文:

  1. The Timezone of the webserver.网络服务器的时区。 Least interesting as no end user ever cares per se where the Server is.最不有趣,因为没有最终用户本身关心服务器在哪里。 But the easiest to acquire.但最容易获得。

  2. The Timezone of the client.客户端的时区。 I can and do collect this from the client, that is in JavaScript on page load I callback with the Client's current timezone and make note of for the session (in fact I record it in the users Session data).我可以并且确实从客户端收集了这个,即在页面加载时在 JavaScript 中我用客户端的当前时区回调并记下 session(实际上我将其记录在用户 Session 数据中)。 That is interesting indeed, far more than the webserver's timezone.这确实很有趣,远远超过网络服务器的时区。

  3. The TimeZone of the submitter.提交者的时区。 Now we're talking business.现在我们谈正事。 And this is the most interesting one for me.这对我来说是最有趣的。 So I create an event that starts at 7pm Hobart time, and you are using the website in Madrid, and look at the event and you see that it's at 7pm (that is you see Hobart time, the time intended by the creator of the event).所以我创建了一个从霍巴特时间晚上 7 点开始的活动,你在马德里使用该网站,然后查看该活动,你会看到它是在晚上 7 点(也就是说你看到的是霍巴特时间,活动创建者打算的时间).

Implementing 3 of course predicates:实现 3 个当然谓词:

  1. That a submitter have a choice of timezones (and I present this with the login prompt, it being prepopulated with the client's timezone as a default)提交者可以选择时区(我将其与登录提示一起显示,默认情况下会预先填充客户的时区)
  2. That we record the submitter's preferred timezone with the event.我们在事件中记录提交者的首选时区。

Now for 1. above you can of course offer an option with every event submission any form field that has a datetime you can offer a Timezone selector too.现在对于 1. 以上,您当然可以为每个事件提交提供一个选项,任何具有日期时间的表单字段您也可以提供时区选择器。 For my needs that is overkill.对于我的需求,这太过分了。 A logged in user typically only wants to deal with local times.登录用户通常只想处理当地时间。 But exploring remote data it's nice to see it with appropriate times of day (and day as TZ impacts the day too).但是探索远程数据时,很高兴在一天中的适当时间看到它(以及一天,因为 TZ 也会影响一天)。

The method I employ is as follows:我采用的方法如下:

  1. Any Django model that has a DateTimeField, has a TimeZoneField following it with the exact self same name but with "_tz" appended.任何具有 DateTimeField 的 Django model 后面都有一个 TimeZoneField,其名称完全相同,但附加了“_tz”。 This records to timezone of DateTimeField.这记录到 DateTimeField 的时区。

  2. I then built a quick custom Transformer:然后我构建了一个快速自定义 Transformer:

from django.db.models import Transform, DateTimeField


class DateTimeLocal(Transform):
    lookup_name = 'local'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        dt = lhs  # has quotes like "table_name"."date_time"
        tz = lhs[:-1] + "_tz" + lhs[-1]  # Add _tz to field name
        return f"{dt} AT TIME ZONE {tz}", params


DateTimeField.register_lookup(DateTimeLocal)

And can use it like so:并且可以像这样使用它:

Blog.objects.filter(created__local>someday)

That is the pseudo-field created__local is now available (it's a Transform).那就是伪字段created__local现在可用(它是一个转换)。

The catch is, if you look at the Transform, that it:问题是,如果您查看 Transform,它会:

  1. Implements Postgresql SQL syntax in as_sql .as_sql中实现 Postgresql SQL 语法。 I have no idea how portable that is and am dubious that it is very portable.我不知道它的便携性如何,我怀疑它是否非常便携。

  2. Predicates the existence of a created_tz TimeZoneField in the model.断言 model 中存在created_tz TimeZoneField。

There is some help here: https://docs.djangoproject.com/en/4.0/howto/custom-lookups/这里有一些帮助: https://docs.djangoproject.com/en/4.0/howto/custom-lookups/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM