2012-11-29 41 views
2

我想创建一个Django模型字段,它表示持续时间与天,小时,分钟和秒文本输入字段在HTML中,并将持续时间存储在数据库中ical格式(RFC5545)。“对象没有任何属性”在自定义Django模型字段

(这关系到我的问题上How to create an ical duration field in Django?

这里是我的方法:

感谢bakkal和波尔。以下是我想出的。

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

我很蠢。问题在于我将该模型定义为duration.py文件,因此与“duration”字段存在命名冲突。我重命名了这个文件,它工作。

+0

我有类似的问题。我将该视图命名为与该模型相同的内容。 – User

0

您是否在更改模型后运行./manage syncdb

如果您决定更改模型,它将不会更新当前数据库。 唯一的方法是重置它,然后运行syncdb。

如果您正在使用SQLite - 只需删除数据库文件,请运行syncdb,它将生成一个包含更新模型的数据库。请注意,它会删除所有现有记录!

相关问题