2

期間を分単位でIntegerFieldに保存しています。フロントエンドフォーム(モデルフォーム)では、入力を1つのフィールドに分単位で分割し、1つのフィールドに時間単位で分割したいと思います。また、InLineFormsetを使用できるようにしたいと思います。これは良い方法で行うことができますか?私はjavascriptを使用できますが、それは私にとって良い解決策のようには見えませんか、それともそうですか?

4

1 に答える 1

5

MultiWidgetを使用したい。フィールド自体をオーバーライドすることをお勧めします。カスタムフィールドを作成するためのドキュメントをご覧ください。

可能であれば、 Pythonのtimedeltaを表す浮動小数点としてデータを保存する価値があるかもしれません。フィールドにいくつかのカスタムメソッドを追加することをお勧めします。フィールドで計算を行う場合は、timedeltaを使用すると便利です。

フォームの検証についても少し読みたいと思うでしょう。

Django 1.4でfloatベースのカスタムフィールドを使用して、次の時間、分、秒のマルチウィジェットをテストしました-

from datetime import timedelta
from django import forms
from django.db import models
from django.core import exceptions, validators


def validate_timedelta(value):
    if not isinstance(value, timedelta):
        raise exceptions.ValidationError('A valid time period is required')


class SplitHoursMinsWidget(forms.widgets.MultiWidget):

    def __init__(self, *args, **kwargs):
        widgets = (
            forms.TextInput(),
            forms.TextInput(),
            forms.TextInput(),
        )
        super(SplitHoursMinsWidget, self).__init__(widgets, *args, **kwargs)

    def decompress(self, value):
        if value:
            return [value.seconds // 3600, (value.seconds // 60) % 60,
                    value.seconds % 60]
        return [None, None, None]

    def format_output(self, rendered_widgets):
        return ("HH:MM:SS " + rendered_widgets[0] + ":" + rendered_widgets[1] +
                 ":" + rendered_widgets[2])

    def value_from_datadict(self, data, files, name):
        hours_mins_secs = [
            widget.value_from_datadict(data, files, name + '_%s' % i)
            for i, widget in enumerate(self.widgets)]
        try:
            time_delta = (timedelta(hours=float(hours_mins_secs[0])) +
                          timedelta(minutes=float(hours_mins_secs[1])) +
                          timedelta(seconds=float(hours_mins_secs[2])))
        except ValueError:
            return None
        else:
            return time_delta


class TimeDeltaFormField(forms.Field):

    widget = SplitHoursMinsWidget


class TimeDeltaField(models.Field):

    __metaclass__ = models.SubfieldBase

    description = "Field to hold a python timedelta object"

    default_validators = [validate_timedelta, ]

    def to_python(self, value):
        if value in validators.EMPTY_VALUES or isinstance(value, timedelta):
            return value
        try:
            return timedelta(seconds=float(value))
        except:
            raise exceptions.ValidationError('A valid time period is required')

    def get_prep_value(self, value):
        return float(value.days * 86400 + value.seconds)

    def get_internal_type(self):
        return 'FloatField'

    def formfield(self, **kwargs):
        defaults = {'form_class': TimeDeltaFormField}
        defaults.update(kwargs)
        return super(TimeDeltaField, self).formfield(**defaults)

これは有用な入力レベルの検証を提供しないことに注意してください(分と秒の両方の入力要素に60を超える入力が可能です)。おそらくそれはjavascriptで最もよく解決できるでしょう。

于 2012-12-11T17:31:23.407 に答える