在Django表单中为只读字段动态创建clean_ *方法

时间:2013-04-08 13:54:46

标签: python django dynamic django-forms

这是此SO question的扩展。

是否有一种简单的方法可以动态生成所需的clean_X方法,以确保不会修改只读表单字段?我可以按照链接问题的建议手动编写方法,但是当你有多个需要以只读方式创建的字段的形式时,新颖性会很快消失。

必须有更好的方法!

解决方案: 根据提供的答案,我决定只覆盖基类中的Form.clean()方法。这是我的表单继承的类,它接受一个参数read_only,它是一个实例属性列表作为字符串。

class FormBase(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.read_only = kwargs.pop("read_only", [])
        super(FormBase, self).__init__(*args, **kwargs)

        #Disable any read only controls
        for f in self.read_only:
            self.fields[f].widget.attrs["readonly"] = True

    def clean(self):
        cleaned_data = super(FormBase, self).clean()
        for f in self.read_only:
            cleaned_data[f] = getattr(self.instance, f)
        return cleaned_data

1 个答案:

答案 0 :(得分:3)

请注意,验证不仅限于form.clean_*方法 - 您也可以使用form.clean()并将cleaned_data值还原为初始实例属性值。如果您在类中定义只读字段的列表(或将其作为参数或其他方式传递),则只需迭代此列表即可重置您的值。

现在你真的坚持动态定义clean_*方法,这里有未经测试,过度简化和完全丑陋的可能解决方案:

class MyForm(...):
    readonly_fields = ("afield", "another",)
    def __init__(self, *args, **kw):
         super(MyForm, self).__init__(*args, **kw)
         for field in self.readonly_fields:
             self.fields[field].widget.attrs['readonly']
             def clean(field=field):
                 # assume fieldname == instance attribute name
                 return getattr(self.instance, field) 
             setattr(self, "clean_%s" % field, clean)

显然,使用Form.clean更容易,更易读,方式更难看。