2009-12-18 44 views
0

我在一個特定項目中經常遇到的情況是,它要求用戶在英尺和英尺中輸入尺寸(對於寬度/深度/高度)。計算需要在該維度上執行,所以我一直在處理一個自定義字段類型,它採用英尺/英寸(例如1'-10「)的維度並使用十進制數字將其保存到數據庫一個用於解析輸入的正則表達式,該字段始終顯示爲最終用戶的英尺英寸(最終目標是編寫一個 方法,以便可以選擇以公制方式顯示,並與measure.py和geodjango進行交互)到目前爲止,我所擁有的絕對不是DRY,但除此之外,我在表單級別驗證時遇到了問題。自定義模型字段本身可以正常工作(從我所見過的),而且我已經編寫了一個表單字段清理方法,它應該可以驗證字段的效果我的問題是如何將表單字段綁定到我的模型表單中以適用於所有寬度/深度/高度字段 我在考慮可能會覆蓋初始化模型(a la self.fields ['depth'] ...),但我並不完全知道在哪裏何去何從......帶驗證的Django自定義模型字段...如何將其綁定回ModelForm

DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$') 
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$') 

class FtInField(models.Field): 
     __metaclass__ = models.SubfieldBase 

     empty_strings_allowed = False 

     def db_type(self): 
       return 'double' 

     def get_internal_type(self): 
       return "FtInField" 

     def to_python(self,value): 
       if value is u'' or value is None: 
         return None 
       if isinstance(value, float): 
         m = FTDCML_PATTERN.match(str(value)) 
         if m is None: 
           raise Exception('Must be an integer or decimal number') 
         feet = int(m.group('feet')) 
         dec_inch = float(m.group('dec_inch') or 0) 
         inch = dec_inch * 12 
         return "%d\'-%.0f\"" % (feet,inch) 
       return value 

     def get_db_prep_value(self,value): 
       if value is u'' or value is None: 
         return None 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise Exception('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       return (feet + (inch/float(12))) 

class FtInField(forms.Field): 
     def clean(self,value): 
       super(FtInField, self).clean(value) 
       if value is u'' or value is None: 
         raise forms.ValidationError('Enter a dimension in X\'-Y" format') 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise forms.ValidationError('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       value = '%d\'-%.0f"' % (feet,inch) 
       return value 

class ProductClass(models.Model): 
     productname = models.CharField('Product Name', max_length=60,blank=True) 
     depth = FtInField('Depth (Feet/Inches)') 
     width = FtInField('Width (Feet/Inches)') 
     height = FtInField('Height (Feet/Inches)') 

class ProductClassForm(forms.ModelForm): 
     depth = FtInField() 
     width = FtInField() 
     height = FtInField() 

     class Meta: 
       model = ProductClass 

class ProductClassAdmin(admin.ModelAdmin): 
     form = ProductClassForm 
+0

爲什麼兩個字段類具有相同的名稱? – 2009-12-18 21:53:56

回答

0

爲避免重複,你可能應該實現處理千丈和英寸的解析爲您的數據類型的類,它應該大大簡化其他代碼。

然後你應該創建一個模型字段和表單域,記住這些是兩個完全獨立的組件。 (你或多或少已經完成了,但這只是爲了完整性)

現在,如果我正在閱讀正確的問題,您希望爲模型字段設置默認窗體字段。爲了實現這一點,你需要在模型字段類上實現formfield()函數。 Ref:the django docs

2

謝謝你,謝謝你們倆。這是我想出的(基於你的建議)。我將努力定義一種數據類型,以便在重複方面做得更好,但與此同時,這也是有效的......(我離得很近,但距離很遠......)你們真棒。謝謝。

DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$') 
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$') 

class FtInFormField(forms.Field): 
     def clean(self,value): 
       super(FtInFormField, self).clean(value) 
       if value is u'' or value is None: 
         raise forms.ValidationError('Enter a dimension in X\'-Y" format') 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise forms.ValidationError('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       value = '%d\'-%.0f"' % (feet,inch) 
       return value 

class FtInField(models.Field): 
     __metaclass__ = models.SubfieldBase 

     empty_strings_allowed = False 

     def db_type(self): 
       return 'double' 

     def get_internal_type(self): 
       return "FtInField" 

     def to_python(self,value): 
       if value is u'' or value is None: 
         return None 
       if isinstance(value, float): 
         m = FTDCML_PATTERN.match(str(value)) 
         if m is None: 
           raise Exception('Must be an integer or decimal number') 
         feet = int(m.group('feet')) 
         dec_inch = float(m.group('dec_inch') or 0) 
         inch = dec_inch * 12 
         return "%d\'-%.0f\"" % (feet,inch) 
       return value 

     def get_db_prep_value(self,value): 
       if value is u'' or value is None: 
         return None 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise Exception('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       return (feet + (inch/float(12))) 

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

class ProductClass(models.Model): 
     productname = models.CharField('Product Name', max_length=60,blank=True) 
     depth = FtInField('Depth (Feet/Inches)') 
     width = FtInField('Width (Feet/Inches)') 
     height = FtInField('Height (Feet/Inches)') 

class ProductClassForm(forms.ModelForm): 

     class Meta: 
       model = ProductClass 

class ProductClassAdmin(admin.ModelAdmin): 
     form = ProductClassForm 
相關問題