1

TIME_ZONE および USE_TZ 設定で日時を保存する私のアプリケーションの大部分は問題ありません。私の質問は、UTC の日時でモデルを保存するにはどうすればよいですか?ユーザーが入力したタイムゾーンに戻す変換が正しいように日時が設定されていますか? 以下に示すモデル、ビュー、フォーム、およびhtml。このコードは、settings.py ファイルで USE_TZ = False の場合に機能しますが、プロジェクト内の他のすべてのタイムゾーンを保持したいと考えています。

モデル:

class TZTestModel(models.Model):
    timezone = TimeZoneField()
    dt = models.DateTimeField()

意見:

class TZTestView(LoginRequiredMixin, TemplateView):
    template_name = "tz_test.html"

    def get_context_data(self, **kwargs):
        return {
            'form': self.form
        }

    def dispatch(self, request, *args, **kwargs):
        self.form = TZTestForm(self.request.POST or None)
        return super(TZTestView, self).dispatch(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        if self.form.is_valid():
            self.form.save()
        return self.render_to_response(self.get_context_data())

形:

class TZTestForm(forms.ModelForm):
    class Meta:
        model = TZTestModel

    def clean(self):
        timezone = self.cleaned_data['timezone']
        dt = self.cleaned_data['dt']
        dt = timezone.localize(dt)
        self.cleaned_data['dt'] = pytz.UTC.normalize(dt.astimezone(pytz.UTC))
        return self.cleaned_data

テンプレート:

<html>
    <body>
        <form method="post">
            {% csrf_token %}
            {{ form }}
            <input type="submit">
        </form>
    </body>
</html>

例:

「US/Alaska」のタイムゾーンと今日の 13:00 の日時を入力し、それを UTC 値として保存してから、「US/Alaska」に変換して正しい値を取得できるようにしたいと考えています。 .

基本的に、あるモデルの日時をアプリケーションとは異なるタイムゾーンに保存しようとしています。タイムゾーンは、日時が指定されているのと同じ形式でユーザーによって指定されています。

4

2 に答える 2

3

オブジェクト レベルのタイムゾーンでも同じ問題が発生しました。

このブログエントリを見つけました。完璧ではありませんが、うまくいきます!複雑すぎません。さらに、管理者の処理が処理されます。

ここにスニペットを貼り付けます:

希望のタイムゾーンでフォームが処理されることを確認します。

def view(request):

    if request.method == 'POST':
        tz_form = TimeZoneForm(request.POST)
        if tz_form.is_valid():
            tz = tz_form.cleaned_data['event_time_zone']
            timezone.activate(tz)
            # Process the full form now
    else:
        # assuming we have an event object already
        timezone.activate(event.event_time_zone)
        # Continue to create form for display on the web page

管理者リスト ビューで正しく表示する

class EventAdmin(admin.ModelAdmin):
    list_display = [..., 'event_datetime_in_timezone', ...]

    def event_datetime_in_timezone(self, event):
        """Display each event time on the changelist in its own timezone"""
        fmt = '%Y-%m-%d %H:%M:%S %Z'
        dt = event.event_datetime.astimezone(pytz_timezone(event.event_time_zone))
        return dt.strftime(fmt)
    event_datetime_in_timezone.short_description = _('Event time')

Admin Add ビューで日時を正しく解釈する

class EventAdmin(admin.ModelAdmin):
    # ...

    # Override add view so we can peek at the timezone they've entered and
    # set the current time zone accordingly before the form is processed
    def add_view(self, request, form_url='', extra_context=None):
        if request.method == 'POST':
            tz_form = TimeZoneForm(request.POST)
            if tz_form.is_valid():
                timezone.activate(tz_form.cleaned_data['event_time_zone'])
        return super(EventAdmin, self).add_view(request, form_url, extra_context)

管理者編集ビューでタイムゾーンを正しく処理する

class EventAdmin(admin.ModelAdmin):
    # ...

    # Override change view so we can peek at the timezone they've entered and
    # set the current time zone accordingly before the form is processed
    def change_view(self, request, object_id, form_url='', extra_context=None):
        if request.method == 'POST':
            tz_form = TimeZoneForm(request.POST)
            if tz_form.is_valid():
                timezone.activate(tz_form.cleaned_data['event_time_zone'])
        else:
            obj = self.get_object(request, unquote(object_id))
            timezone.activate(obj.event_time_zone)
        return super(EventAdmin, self).change_view(request, object_id, form_url, extra_context)
于 2014-10-14T23:17:51.603 に答える
0

編集: フォーム フィールドのペーストビン ソース: http://pastebin.com/j4TnnHTS さらなる議論: https://code.djangoproject.com/ticket/21300

これを行う方法は、素朴な日時を返すカスタムフォームフィールドを作成し、それをユーザーが指定したタイムゾーンに変換してから、UTC に変換することです。

カスタムフィールド:

class DateTimeNoTimeZoneField(forms.DateTimeField):
    def to_python(self, value):
        """
        Validates that the input can be converted to a datetime. Returns a
        Python datetime.datetime object.
        """
        if value in validators.EMPTY_VALUES:
            return None
        if isinstance(value, datetime.datetime):
            return value
        if isinstance(value, datetime.date):
            return datetime.datetime(value.year, value.month, value.day)
        if isinstance(value, list):
            # Input comes from a SplitDateTimeWidget, for example. So, it's two
            # components: date and time.
            if len(value) != 2:
                raise ValidationError(self.error_messages['invalid'])
            if value[0] in validators.EMPTY_VALUES and value[1] in validators.EMPTY_VALUES:
                return None
            value = '%s %s' % tuple(value)
                # Try to coerce the value to unicode.
        unicode_value = force_text(value, strings_only=True)
        if isinstance(unicode_value, six.text_type):
            value = unicode_value.strip()
        # If unicode, try to strptime against each input format.
        if isinstance(value, six.text_type):
            for format in self.input_formats:
                try:
                    return self.strptime(value, format)
                except (ValueError, TypeError):
                    continue
        raise ValidationError(self.error_messages['invalid'])

形:

class TZTestForm(forms.ModelForm):
    dt = DateTimeNoTimeZoneField()

    class Meta:
        model = TZTestModel

    def clean(self):
        tz = self.cleaned_data['timezone']
        dt = self.cleaned_data['dt']
        dt = pytz.UTC.normalize(tz.localize(dt).astimezone(pytz.UTC))
        self.cleaned_data['dt'] = dt
        return self.cleaned_data
于 2013-10-22T01:05:26.047 に答える