Django自定义模型字段与验证...如何挂钩回到ModelForm [英] Django Custom Model Field with Validation...how to hook it back to ModelForm

查看:165
本文介绍了Django自定义模型字段与验证...如何挂钩回到ModelForm的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与一个特定项目有一个常见的情况是,它需要用户输入尺寸(宽度/深度/高度),以英尺和英寸为单位。需要在该维度上执行计算,因此我一直在使用以英尺(英寸)为单位的自定义字段类型(例如,1'-10),并将其作为十进制数保存到数据库中,使用一个正则表达式来解析输入,该字段始终以最终用户的身份显示为英尺(最终目标是编写
方法,以便可以以度量标准显示,并与measure.py进行交互,和geodjango的东西),我到目前为止绝对不是干,但除此之外,我在表单层面验证有困难。自定义模型领域本身正常工作(从我看过),和我已经写了一个表单域清理方法,该方法应该用于验证该字段。我的问题是如何将该表单字段挂回到我的模型窗体中以适用于所有宽度/深度/高度字段
我是认为可能是模仿模式的初始化的覆盖(一个la self.fields ['depth'] ...),但我不太确定从哪里去...

A common occurrence I have with one particular project is that it requires the user to enter dimensions (for width/depth/height) in Feet and Inches. Calculations are needed to be performed on that dimension, so I've been working on a custom field type that takes in a dimension in Feet/Inches (eg. 1'-10") and saves it to the database as a decimal number using a regex to parse the input. The field displays to the end-user as feet-inches at all times (with the eventual goal of writing a method to be able to optionally display in metric, and interact with measure.py, and geodjango stuff). What I have so far is definitely not DRY, but aside from that, I'm having trouble with validation at the form level. The custom model field itself works properly (from what I've seen), and I've written a form field clean method which should work to validate the field. My question is how to hook that form field back into my model form to work for all the width/depth/height fields. I'm thinking maybe an override of the init on the modelform (a la self.fields['depth']...) , but I'm not quite sure where to go from here...

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


推荐答案

为了避免重复,您应该可以实现一个数据类型类,用于处理对于feets和inches的解析,它应该大大简化其他代码。

To avoid duplication you should probably implement a data type class that handles the parsing of feets and inches for you, it should greatly simplify the other code.

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

Then you should create a model field and form field, keeping in mind that these are two COMPLETELY SEPARATE components. (which you more or less have already done, but this is just for completeness)

现在,如果我正在阅读问题,你想设置默认表单字段为您的模型字段。为了方便你,你想在你的model field类上实现formfield()函数。参考: django docs

Now, if I'm reading the question right, you want to set the default form field for your model field. To facilitate this you want to implement the formfield() function on your model field class. Ref: the django docs

这篇关于Django自定义模型字段与验证...如何挂钩回到ModelForm的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆