2012-11-29 67 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,它將生成一個包含更新模型的數據庫。請注意,它會刪除所有現有記錄!

相關問題