Correct way to define a ModelForm metaclass
我要做的是创建一个动态模型窗体,它基于要在ModelAdmin中使用的类属性生成额外的字段。比如:
1 2 3 4 5 | class MyModelForm(forms.ModelForm): config_fields = ('book_type', 'is_featured', 'current_price__is_sale') class MyModelAdmin(admin.ModelAdmin): form = MyModelForm |
在这种情况下,MyModelForm将通过执行一些自省,基于config_fields属性生成字段。到目前为止,我的方法是这样的(基于这个答案https://stackoverflow.com/a/6581949/677985):
1 2 3 4 5 6 7 8 9 10 11 12 13 | class ConfigForm(type): def __new__(cls, name, bases, attrs): if 'config_fields' in attrs: for config_field in attrs['config_fields']: # ... (removed for clarity) attrs.update(fields) return type(name, bases, attrs) class MyModelForm(forms.ModelForm): __metaclass__ = ConfigForm config_fields = ('book_type', 'is_featured', 'current_price__is_sale') |
号
这种方法非常有效,但我不太满意它,原因有几个:
我尝试实现第三个项目,结果是额外的字段没有显示在管理表单中。如果有人能帮我解决这个问题,或者至少能给我指明正确的方向,我将不胜感激。
我知道使用一个元类来解决这个问题可能有点过头了,并且我猜想部分问题在于ModelForm的继承链中已经有一个或两个元类了。所以,如果有人有一个替代的解决方案可以达到同样的效果,那我也会很高兴的。
这个怎么样,
基本上,任何扩展您的stepForm的表单都会有您想要的元类,在下面的例子中,它是stepFormMetaClass,请注意,如果您在某个form.py文件中定义了表单,那么您需要在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.forms.forms import DeclarativeFieldsMetaclass class StepFormMetaclass(DeclarativeFieldsMetaclass): ....... def __new__(meta_class, name, bases, attributes): ..... return DeclarativeFieldsMetaclass.__new__(meta_class, name, bases, attributes) class StepForm(six.with_metaclass(StepFormMetaclass, forms.Form, StepFormMixin)): def __init__(self, *args, **kwargs): super(StepForm, self).__init__(*args, **kwargs) def as_p(self): return ...... |
号
我相信
相反,您应该能够直接使用
例子:
1 2 3 4 5 6 7 | config_fields = ('book_type', 'is_featured', 'current_price__is_sale') # the below is an example, you need more work to construct the proper attrs attrs = dict((f, forms.SomeField) for f in config_fields) ConfigModelForm = type('DynamicModelForm', (forms.ModelForm,), attrs) class MyModelAdmin(admin.ModelAdmin): form = ConfigModelForm |
如果需要,可以将第一部分包装在函数中,并在ModelAdmin中为表单属性调用它。
有关使用类型的链接和讨论,请参阅此处的答案。