【问题标题】:Add form fields to django form dynamically将表单字段动态添加到 django 表单
【发布时间】:2026-01-07 12:10:02
【问题描述】:

由于 BD 设计取决于值,数据存储在不同的单元格中,我必须动态添加表单字段。我在想这个:

class EditFlatForm(BaseModelForm):


    on_sale = forms.BooleanField(required=False)
    on_rent = forms.BooleanField(required=False)


    class Meta:

        model = Flat

        fields = ('title', 'flat_category', 'description')

        ...


    def __init__(self, *args, **kwargs):

        super(EditFlatForm, self).__init__(*args,**kwargs)


        flat_properties = FlatProperty.objects.all()

        for p in flat_properties:

            if p.type_value == 1:
                # Text
                setattr(self, p.title, forms.CharField(label=p.human_title, required=False))
            elif p.type_value == 2:
                # Number
                setattr(self, p.title, forms.IntegerField(label=p.human_title, required=False))
            else:
                # Boolean
                setattr(self, p.title, forms.BooleanField(label=p.human_title, required=False))

但是字段没有被添加,我错过了什么?

【问题讨论】:

  • 你当然不应该从 BaseModelForm 继承。
  • BaseModelForm 只是我用来处理标签的一个类,为什么不用呢?
  • 也许是self.fields[p.title] = forms....?假设 p.title 是一个字符串
  • @MihaiZamfir omg,当然,我在想什么,干杯伙伴,添加它作为回应,我会接受它,但我认为这个问题将是非常多余的
  • 抱歉,我以为是forms.BaseModelForm。

标签: python django forms


【解决方案1】:

我建议使用type 即时创建表单。因此,您需要创建一个函数,该函数将生成您希望在表单中包含的所有字段的列表,然后使用它们来生成表单,如下所示:

def get_form_class():
    flat_properties = FlatProperty.objects.all()
    form_fields = {}
    for p in flat_properties:
        if p.type_value == 1:
        form_fields['field_{0}'.format(p.id)] = django.forms.CharField(...)
        elif p.type_value == 2:
            form_fields['field_{0}'.format(p.id)] = django.forms.IntegerField(...)
        else:
            form_fields['field_{0}'.format(p.id)] = django.forms.BooleanField(...)
    # ok now form_fields has all the fields for our form
    return type('DynamicForm', (django.forms.Form,), form_fields  )

现在您可以在任何您想使用表单的地方使用get_form_class,例如

form_class = get_form_class()
form = form_class(request.GET) 
if form.is_valid() # etc 

有关更多信息,您可以查看我关于使用 django 创建动态表单的帖子: http://spapas.github.io/2013/12/24/django-dynamic-forms/

更新以解决 OP 的评论(但是如何利用 ModelForm 提供的所有功能?):您可以从 ModelForm 继承您的动态表单。或者,更好的是,您可以创建一个继承自 ModelForm 的类并定义所有必需的方法和属性(如 clean__init__Meta 等)。然后通过将 type 调用更改为 type('DynamicForm', (CustomForm,), form_fields ) 来继承该类!

【讨论】:

  • 那么如何利用 ModelForm 提供的所有功能呢?
  • 动态创建的表单最终有一个奇怪的包名称 - 如果你尝试这个 str(type('PostForm2', (Form,), {})) - 它返回 <class 'django.forms.widgets.PostForm2'> - 我觉得如果表单涉及异常并显示在stacktrace,那真的会让人迷惑......
【解决方案2】:

假设p.title 是一个字符串变量,那么这应该可以工作:

if p.type_value == 1:
     # Text
     self.fields[p.title] = forms.CharField(label=p.human_title, required=False))

【讨论】: