【问题标题】:Django models __unicode__: How to return a value containing localized datetimes?Django 模型 __unicode__:如何返回包含本地化日期时间的值?
【发布时间】:2015-06-01 01:16:57
【问题描述】:

我有一个本地化的 Django 应用程序,本地化效果很好,配置还可以……

由于表单需要,我使用__unicode__模型的方法来渲染ModelChoiceFields,但是如何在unicode返回中格式化本地化日期?

在这种方法中我无法访问当前时区,如何正确地向我的用户显示我的 TimeSpanList?目前,它显示 UTC。我尝试了 django.template.defaultfilters.date 和 Simon Charette 的 django.utils.formats.localize,但没有帮助,因为他们可能缺乏上下文数据……

class TimeSpan(models.Model):
    start = models.DateTimeField(_("start"))
    end = models.DateTimeField(_("end"))

    def __unicode__(self):
        return u"from UTC:{0} to UTC:{1}".format(self.start, self.end)

class TimeSpanChooserForm(forms.Form):
    time_span = forms.ModelChoiceField(
        label=_("time span"), queryset=TimeSpan.objects.all())

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request", None)
        super(TimeSpanChooserForm, self).__init__(*args, **kwargs)

如何在没有当前请求对象的情况下知道当前语言环境来本地化这些日期时间? (如果有办法)

注意:对我来说__unicode__ 似乎是在 ModelChoiceField 中显示条目的唯一方法。

注 2:对我来说,Yuji 'Tomita' Tomita 评论是目前最好的答案,但它缺乏可用的例子……

【问题讨论】:

  • 你不能。不要在模板中使用 unicode 方法,直接访问日期。
  • 但是对于一个表单处理的选择字段,那你怎么做呢?
  • 您可以随时将请求传递给表单。
  • 您不应该考虑严格修改__unicode__ 以确定默认情况下在ChoiceField 中填充的内容。这些是方便的自动默认值。除此之外,我会直接修改表格。转换为客户端区域设置对于视图和请求来说似乎非常本地化。否则,这些 TimeSpan 的管理员表示将默认为您自己的管理员 TZ。研究动态修改选择字段选项!
  • 我添加了一个表单库,以便您可以在我能够接受的完整答案中完成它,您将如何从此处更改具有本地化日期的渲染?

标签: django datetime django-models timezone django-i18n


【解决方案1】:

您可以使用django.utils.formats.localize 函数。

from django.db import models
from django.utils.formats import localize
from django.utils.translation import ugettext

class TimeSpan(models.Model):
    start = models.DateTimeField(_('start'))
    end = models.DateTimeField(_('end'))

    def __unicode__(self):
        return ugettext("from %(start)s to %(end)s") % {
            'start': localize(self.start),
            'end': localize(self.end),
        }

您可以使用这些操作测试以下工作。

from django.utils import timezone
from django.utils.translation import override

with override('fr'):
    print(TimeSpan(start=timezone.now(), end=timezone.now()))

with override('en'):
    print(TimeSpan(start=timezone.now(), end=timezone.now()))

两者都应该显示不同的格式。

如果您想确保日期显示在特定时区,您必须确保在您的设置中设置USE_TZ = True,并将TIME_ZONE 设置设置为您要使用的设置。您可以使用中间件调用 django.utils.timezone.activate 并使用所需的时区来为每个请求设置此时区。

您也可以使用 django-sundial 包来为您处理这个问题。

【讨论】:

  • 本地化功能现在如何成为良好的语言环境?我刚试过,它仍然返回 UTC 日期时间……
  • 如果您希望 Django 考虑浏览器的区域设置偏好,您必须确保 LocaleMiddleware 在您的 MIDDLEWARE_CLASSES 设置中,USE_I18NUSE_L10N 设置都设置为 @ 987654332@ 并且您在LANGUAGE 设置中有您想要支持的语言条目。
  • 我的设置没问题,django模板或日期时间字段(django表单)显示的所有日期都很好……
【解决方案2】:

试试这个:

def __unicode__(self):
    return u'%s %s'%(self.start,self.end)

使用它购买它将返回组合的开始和结束日期时间对象。这对我有用

【讨论】:

  • 我的问题是关于本地化这些日期时间......我想答案更复杂,我从你的建议开始,但它显示 UTC 日期时间而不是本地化数字......
【解决方案3】:

感谢您提醒我这个问题。一个完整的答案有点复杂。

我创建了一个演示方法来展示这一点。运行test() 以查看输出。

剩下的挑战是获取客户端时区。这可能会通过一些 JavaScript 来完成,这些 JavaScript 将参数添加到您的 GET/POST 或添加要在视图中读取的自定义标头。

由于这是一个未知数,我只是用一个返回随机时区的方法将其排除。您应该更新它以反映您的客户端时区检索方法。

这是一个自我记录的例子:

型号

from django.utils.formats import localize


class TimeSpan(models.Model):
    start = models.DateTimeField("start")
    end = models.DateTimeField("end")

    def __unicode__(self):
        return u"from UTC:{0} to UTC:{1}".format(self.start, self.end)

表格

from django import forms

class TimeSpanChooserForm(forms.Form):
    time_span = forms.ModelChoiceField(
        label=("time span"), queryset=TimeSpan.objects.all())

    def __init__(self, *args, **kwargs):
        # get request and TZ from view. This is a special form..
        self.request = kwargs.pop("request", None)
        self.tz = kwargs.pop('tz', None)
        super(TimeSpanChooserForm, self).__init__(*args, **kwargs)

        # modify the choices attribute to add custom labels.
        self.fields['time_span'].choices = [
            self.make_tz_aware_choice(self.request, timespan) for timespan in self.fields['time_span'].queryset
        ]

    def make_tz_aware_choice(self, request, timespan):
        """ Generate a TZ aware choice tuple.
        Must return (value, label). In the case of a ModelChoiceField, (instance id, label).
        """
        start = timespan.start.replace(tzinfo=self.tz)
        end = timespan.end.replace(tzinfo=self.tz)
        label = "From {tz} {start} to: {tz} {end}".format(
            start=start,
            end=end,
            tz=self.tz,
        )
        return (timespan.id, label)

查看

import random
import pytz

from django import http
from django import template

def view(request):
    """ Render a form with overridden choices respecting TZ
    """
    def get_tz_from_request(request):
        """ Get the client timezone from request.
        How you do this is up to you. Likely from JS passed as a parmeter.
        """
        random_timezone = random.choice(pytz.all_timezones)
        return pytz.timezone(random_timezone)

    form = TimeSpanChooserForm(request.POST or None, request=request, tz=get_tz_from_request(request))
    ctx = template.Context({
        'form': form,
    })
    rendered_template = template.Template("{{ form }}").render(ctx)
    return http.HttpResponse(rendered_template)


def test():
    from django.test import RequestFactory

    rf = RequestFactory()
    r = rf.get('/')

    for i in range(10):
        print str(view(r))

【讨论】:

  • 哈哈,这肯定是我一直在等待的答案,谢谢。
猜你喜欢
  • 2016-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-02
  • 2016-07-17
  • 1970-01-01
  • 2020-03-14
  • 2016-05-13
相关资源
最近更新 更多