Python 定义ModelForm元类的正确方法

Python 定义ModelForm元类的正确方法,python,django,metaclass,modelform,Python,Django,Metaclass,Modelform,我要做的是创建一个动态ModelForm,它根据ModelAdmin中使用的一个类属性生成额外的字段。比如: class MyModelForm(forms.ModelForm): config_fields = ('book_type', 'is_featured', 'current_price__is_sale') class MyModelAdmin(admin.ModelAdmin): form = MyModelForm 在本例中,MyModelForm将通过执行

我要做的是创建一个动态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属性生成字段。到目前为止,我的方法是这样的(基于这个答案):

这种方法很有效,但我不太满意,原因有几个:

  • 验证似乎不起作用,但目前这只是一个小问题
  • 我不太清楚为什么需要“attrs中的if config_字段:”-condition,但它是必需的
  • 我希望MyModelForm继承而不是设置_元类___)属性,这样基类就可以很容易地重用,并允许我轻松地重写clean和_init方法
  • 我尝试实现第三项,结果是额外的字段没有显示在管理表单中。如果有人能帮我解决这个问题,或者至少给我指出正确的方向,我将不胜感激


    我知道使用元类来实现这一点可能有些过分,我想部分问题在于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中为表单属性调用它

    有关使用类型的链接和讨论,请参阅。

    这个怎么样

    基本上,任何扩展StepForm的表单都会有您想要的元类,在下面的例子中,它是StepFormMetaclass,请注意,如果您在某个form.py文件中定义了表单,那么您需要将表单导入
    \uuuuuuuuu init\uuuuuuuuuuuuuuupy
    中,以便在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 ......
    

    谢谢,这种方法不允许我使用我一直在寻找的继承结构,但它确实涉及到一些我还没有完全理解的东西,比如meta-classes。@j.koch唯一可用的其他选择是将django提供的
    ModelFormMetaclass
    与您自己的结合起来。您也不能将该元类划分为子类。至于继承基表单,您可以通过组合子类上的元类来实现。@j.koch有关更多信息,请参见此处的答案:
    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 ......