0

我在一个特定项目中经常遇到的情况是,它要求用户以英尺和英寸为单位输入尺寸(宽度/深度/高度)。需要对该尺寸执行计算,因此我一直在研究一种自定义字段类型,该类型采用英尺/英寸为单位的尺寸(例如 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
4

2 回答 2

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
于 2009-12-19T00:40:10.323 回答
0

为避免重复,您可能应该实现一个为您处理英尺和英寸解析的数据类型类,它应该大大简化其他代码。

然后你应该创建一个模型字段和表单字段,记住这是两个完全独立的组件。(您或多或少已经做过,但这只是为了完整性)

现在,如果我没看错,您想为模型字段设置默认表单字段。为了促进这一点,您希望在模型字段类上实现 formfield() 函数。参考:django 文档

于 2009-12-18T22:02:35.833 回答