如何在Django中获取当前用户的时区?

9
我正在尝试让我的Django应用与当前用户的时区配合工作,但是我没有得到任何结果...
在我的settings.py文件中,我设置了:
TIME_ZONE = 'UTC'

在我的views.py中,我在代码的顶部设置了:
activate(settings.TIME_ZONE)

但这个不起作用,在创建帖子的时候,它获取了我上次使用的时区是“马德里”,而不是我的当前时区。

有没有办法让这个工作起来?

谢谢!


你能添加一些信息和代码吗? 在你的模型中,你是使用 from django.utils import timezonetimezone.now() 还是像 models.DateTimeField(auto_now_add=True) 这样的方式? - Henri
1
根据您所说,您有一个时区,即UTC。因此,Django将使用该时区作为默认时区,然后您在视图中激活了该(相同的)时区。这显然不会有任何不同。本地化Django可能相当复杂,但可以从时区文档开始;https://docs.djangoproject.com/en/3.1/topics/i18n/timezones/ - markwalker_
4个回答

13
希望这能帮到某人。由于Django无法自动检测用户的时区,我想到了在登陆页面上使用JS将用户的时区保存在cookie中的方法。
在base.html中放置。
<script>
    // Timezone settings
    const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; // e.g. "America/New_York"
    document.cookie = "django_timezone=" + timezone;
</script>

我按照官方Django文档中指示的步骤进行了一些微小的修改。
import zoneinfo
from django.utils import timezone

class TimezoneMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        try:
            # get django_timezone from cookie
            tzname = request.COOKIES.get("django_timezone")
            if tzname:
                timezone.activate(zoneinfo.ZoneInfo(tzname))
            else:
                timezone.deactivate()
        except Exception as e:
            timezone.deactivate()

        return self.get_response(request)

4

这里是这个Django时区的来源。

将以下中间件添加到MIDDLEWARE中:

import pytz

from django.utils import timezone

class TimezoneMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        tzname = request.session.get('django_timezone')
        if tzname:
            timezone.activate(pytz.timezone(tzname))
        else:
            timezone.deactivate()
        return self.get_response(request)

创建一个视图,可以设置当前时区:
from django.shortcuts import redirect, render

def set_timezone(request):
    if request.method == 'POST':
        request.session['django_timezone'] = request.POST['timezone']
        return redirect('/')
    else:
        return render(request, 'template.html', {'timezones': pytz.common_timezones})

在template.html中包含一个表单,该表单将POST到此视图:
{% load tz %}
{% get_current_timezone as TIME_ZONE %}
<form action="{% url 'set_timezone' %}" method="POST">
    {% csrf_token %}
    <label for="timezone">Time zone:</label>
    <select name="timezone">
        {% for tz in timezones %}
        <option value="{{ tz }}"{% if tz == TIME_ZONE %} selected{% endif %}>{{ tz }}</option>
        {% endfor %}
    </select>
    <input type="submit" value="Set">
</form>

在表单中启用时区支持后,Django会将表单中输入的日期时间解释为当前时区,并在cleaned_data中返回带有时区信息的datetime对象。

如果当前时区对于不存在或因夏令时转换(由pytz提供的时区会执行此操作)而存在歧义的日期时间引发异常,则这些日期时间将报告为无效值。

在模板中启用时区支持后,Django会将带有时区信息的datetime对象,在其呈现到模板上时转换为当前时区。这与格式本地化非常相似。

警告

Django不会转换天真的datetime对象,因为它们可能存在歧义,并且当启用时区支持时,您的代码不应该生成天真的datetime对象。但是,您可以使用下面描述的模板过滤器强制进行转换。

转换为本地时间并不总是合适的 - 您可能正在为计算机而不是人类生成输出。tz模板标签库提供的以下过滤器和标签允许您控制时区转换。

模板标签:

localtime¶

启用或禁用包含块中带有时区信息的datetime对象转换为当前时区。

就模板引擎而言,此标记与USE_TZ设置具有完全相同的效果。它允许更精细的控制转换。

要激活或停用模板块的转换,请使用:

{% load tz %}

{% localtime on %}
    {{ value }}
{% endlocaltime %}

{% localtime off %}
    {{ value }}
{% endlocaltime %}

注意

在 {% localtime %} 块内,USE_TZ 的值不被尊重。

timezone 设置或取消包含块内的当前时区。当未设置当前时区时,将应用默认时区。

{% load tz %}

{% timezone "Europe/Paris" %}
    Paris time: {{ value }}
{% endtimezone %}

{% timezone None %}
    Server time: {{ value }}
{% endtimezone %}

get_current_timezone¶ 使用get_current_timezone标记可以获取当前时区的名称:

{% get_current_timezone as TIME_ZONE %}

另外,您可以激活tz()上下文处理器并使用TIME_ZONE上下文变量。


0
你可以自动检测并应用用户当前的时区,而不仅仅将一个时区设置为TIME_ZONEsettings.py中。
你可以查看我的答案,解释了两种方法,一种是不使用django-tz-detect,另一种是使用它来实现这个功能。

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接