2

HTMLで日、時間、分、秒のテキスト入力フィールドで期間を表し、ical形式(RFC5545)を使用して期間をデータベースに保存するDjangoモデルフィールドを作成しようとしています。

(これは、Djangoでical期間フィールドを作成する方法に関する私の質問に関連していますか? )

これが私のアプローチです:

bakkalとPolに感謝します。以下は私が思いついたものです。

from django.db import models
from icalendar.prop import vDuration
from django.forms.widgets import MultiWidget
from django.forms import TextInput, IntegerField
from django.forms.util import flatatt
from django.forms.fields import MultiValueField
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _
from django.core import validators
from datetime import timedelta

def is_int(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

class Widget_LabelInputField(TextInput):
    """
    Input widget with label
    """
    input_type="numbers"
    def __init__(self, labelCaption, attrs=None):
        self.labelCaption = labelCaption
    super(Widget_LabelInputField, self).__init__(attrs)

    def _format_value(self, value):
        if is_int(value):
            return value
        return '0'

    def render(self, name, value, attrs=None):
        if value is None:
            value = '0'
        final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
        if value != '':
            # Only add the 'value' attribute if a value is non-empty.
            final_attrs['value'] = force_unicode(self._format_value(value))
        if (self.labelCaption):
        typeString = self.labelCaption + ': '
        else:
            typeString = ''           
        return mark_safe(u'' + typeString + '<input%s style=\'width: 30px; margin-right: 20px\'/>' % flatatt(final_attrs))



class Widget_DurationField(MultiWidget):
    """
    A Widget that splits duration input into two <input type="text"> boxes.
    """

    def __init__(self, attrs=None):
        widgets = (Widget_LabelInputField(labelCaption='days', attrs=attrs),
                   Widget_LabelInputField(labelCaption='hours', attrs=attrs),
                   Widget_LabelInputField(labelCaption='minutes', attrs=attrs),
                   Widget_LabelInputField(labelCaption='seconds', attrs=attrs)
                   )
        super(Widget_DurationField, self).__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            duration = vDuration.from_ical(value)
            return [str(duration.days), str(duration.seconds // 3600), str(duration.seconds % 3600 // 60), str(duration.seconds % 60)]
        return [None, None, None, None]



class Forms_DurationField(MultiValueField):
    widget = Widget_DurationField
    default_error_messages = {
        'invalid_day': _(u'Enter a valid day.'),
        'invalid_hour': _(u'Enter a valid hour.'),
        'invalid_minute': _(u'Enter a valid minute.'),
        'invalid_second': _(u'Enter a valid second.')
    }

    def __init__(self, *args, **kwargs):
        errors = self.default_error_messages.copy()
        if 'error_messages' in kwargs:
            errors.update(kwargs['error_messages'])
        fields = (
            IntegerField(min_value=-9999, max_value=9999,
                      error_messages={'invalid': errors['invalid_day']},),
            IntegerField(min_value=-9999, max_value=9999,
                      error_messages={'invalid': errors['invalid_hour']},),
            IntegerField(min_value=-9999, max_value=9999,
                      error_messages={'invalid': errors['invalid_minute']},),
            IntegerField(min_value=-9999, max_value=9999,
                      error_messages={'invalid': errors['invalid_second']},),
        )
        super(Forms_DurationField, self).__init__(fields, *args, **kwargs)

    def compress(self, data_list):
        if data_list:
            if data_list[0] in validators.EMPTY_VALUES:
                raise ValidationError(self.error_messages['invalid_day'])
            if data_list[1] in validators.EMPTY_VALUES:
                raise ValidationError(self.error_messages['invalid_hour'])
            if data_list[2] in validators.EMPTY_VALUES:
                raise ValidationError(self.error_messages['invalid_minute'])
            if data_list[3] in validators.EMPTY_VALUES:
                raise ValidationError(self.error_messages['invalid_second'])

            return vDuration(timedelta(days=data_list[0],hours=data_list[1],minutes=data_list[2],seconds=data_list[3]))
        return None




class Model_DurationField(models.Field):
    description = "Duration"

    def __init__(self, *args, **kwargs):
        super(Model_DurationField, self).__init__(*args, **kwargs)

    def db_type(self, connection):
        return 'varchar(255)'

    def get_internal_type(self):
        return "Model_DurationField"

    def to_python(self, value):
        if isinstance(value, vDuration) or value is None:
            return value

        return vDuration.from_ical(value) 

    def get_prep_value(self, value):
        return value.to_ical() 

    def formfield(self, **kwargs):
        defaults = {
            'form_class': Forms_DurationField,
            'required': not self.blank,
            'label': capfirst(self.verbose_name),
            'help_text': self.help_text}
        defaults.update(kwargs)
        return super(Model_DurationField, self).formfield(**defaults)

次のモデルで動作します。

class TestModel(models.Model):
    ID = models.CharField(max_length=255)
    start = models.DateTimeField(null=True)
    #duration = models.CharField(max_length=255,null=True) commented out
    otherDuration = duration.Model_DurationField(null=True)

しかし、これにはありません:

class TestModel(models.Model):
    ID = models.CharField(max_length=255)
    start = models.DateTimeField(null=True)
    duration = models.CharField(max_length=255,null=True)  # not commented out
    otherDuration = duration.Model_DurationField(null=True)

次のエラーが発生します。

File "/somepath/models.py", line 5, in TestModel
    otherDuration = duration.Model_DurationField(null=True)
AttributeError: 'CharField' object has no attribute 'Model_DurationField'

それは私を困惑させます...Pythonは私のフィールドを前のフィールドの属性と見なしているようですが、それがCharFieldである場合に限ります。何か案は?

4

2 に答える 2

4

私は愚かでした。問題は、モデルがduration.pyで定義されているファイルに名前を付けたため、「duration」フィールドとの名前の競合があったことです。ファイルの名前を変更しましたが、機能しました。

于 2012-11-29T21:56:02.247 に答える
0

./manage syncdbモデルを変更した後に実行しましたか?

モデルを変更することにした場合、現在のデータベースは更新されません。唯一の方法は、リセットしてからsyncdbを実行することです。

SQLiteを使用している場合は、dbファイルを削除し、syncdbを実行すると、更新されたモデルでデータベースが生成されます。既存のすべてのレコードが削除されることに注意してください。

于 2012-11-29T21:50:58.710 に答える