我在一个特定项目中经常遇到的情况是,它要求用户以英尺和英寸为单位输入尺寸(宽度/深度/高度)。需要对该尺寸执行计算,因此我一直在研究一种自定义字段类型,该类型采用英尺/英寸为单位的尺寸(例如 1'-10")并将其作为十进制数保存到数据库中用于解析输入的正则表达式。该字段始终以英尺英寸的形式向最终用户显示(最终目标是编写一个能够选择以公制显示的方法,并与 measure.py 和 geodjango 的东西进行交互)。到目前为止我所拥有的绝对不是 DRY,但除此之外,我在表单级别的验证方面遇到了麻烦。自定义模型字段本身可以正常工作(据我所见),而且我 已经编写了一个表单字段清理方法,该方法应该可以验证该字段。我的问题是如何将该表单字段连接回我的模型表单以适用于所有宽度/深度/高度字段。我在想可能会覆盖模型表单上的 init (a la self.fields['depth']...) ,但我不太确定从这里去哪里...
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