我要做的是创建一个动态ModelForm,根据要在ModelAdmin中使用的类属性之一生成额外的字段。类似的东西:
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):
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')
这种方法效果很好,但由于以下几个原因,我对此并不满意:
我尝试实现第三项,结果是额外字段没有显示在admin-form中。如果有人能帮助我解决这个问题,或者至少指出我正确的方向,我将不胜感激。
我知道使用元类可能有点过分,并且会猜测问题的一部分是ModelForm在其继承链中已经有一个或两个元类。因此,如果任何人有一个替代解决方案来实现同样的目标,那将使我感到高兴。
答案 0 :(得分:0)
我相信ModelForm
已经有了一个元类,但你通过设置自己来覆盖它。这就是为什么你没有得到验证或任何其他内置的模型形式的好处。
相反,您应该能够直接使用type
创建ModelForm
,它将描述您想要的类型,但仍会导致ModelForms元类执行其操作。
示例:
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中为表单属性调用它。
有关使用类型的链接和讨论,请参阅my answer here。
答案 1 :(得分:0)
这个怎么样,
基本上任何扩展StepForm的表单都会在StepFormMetaclass下面的情况下使用你想要的元类,请注意,如果你在某个form.py文件中定义了表单,则需要导入___init___.py
中的表单,以便在django启动序列期间执行它。
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 ......