2012-11-29 4 views
2

HTML의 일,시, 분 및 초 텍스트 입력 필드가있는 기간을 나타내는 Django 모델 필드를 만들고 해당 기간을 사용하여 db에 저장하려고합니다. 형식 (RFC5545)."개체에 특성이 없습니다"Django 사용자 지정 모델 필드에

감사 bakkal 및 폴 :

(이이 How to create an ical duration field in Django?에 내 질문에 관련이있다) 여기

내 접근 방식입니다. 아래는 내가 생각해내는 것입니다.

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' 

나 퍼즐 ... 파이썬은 내 필드를 이전 필드의 특성이지만 CharField 인 경우에만 어떤 아이디어?

답변

4

나는 바보 같았다. 문제는 모델에 duration.py가 정의 된 파일의 이름을 지정했기 때문에 "duration"필드와 이름이 충돌합니다. 나는 파일의 이름을 바꾸었고 효과가 있었다.

+0

비슷한 문제가 있습니다. 뷰의 이름을 모델 이름과 동일하게 지정했습니다. – User

0

모델을 변경 한 후 ./manage syncdb을 실행 했습니까?

모델을 변경하기로 결정하면 현재 데이터베이스가 업데이트되지 않습니다. 유일한 방법은 재설정하고 syncdb를 실행하는 것입니다.

SQLite를 사용하는 경우 db 파일을 삭제하고 syncdb를 실행하면 업데이트 된 모델로 데이터베이스가 생성됩니다. 기존 레코드가 모두 삭제됩니다.

관련 문제