Django 1.9.7:如何为ModelForm动态添加运行时非模型字段?
在Django 1.9.7中运行时为ModelForm添加模型未定义字段的方法
要实现运行时动态添加字段(尤其是需要动态获取选项的ChoiceField),核心思路就是利用表单的__init__方法操作字段字典——Django表单的所有字段都存储在self.fields中,我们可以在运行时灵活地往里面添加新字段,还能动态设置字段的选项或属性。
基础实现:动态添加带运行时选项的ChoiceField
比如我们需要根据数据库查询结果动态生成选项,代码可以这么写:
from django import forms from .models import Example, SomeOtherModel class ExampleForm(forms.ModelForm): class Meta: model = Example fields = '__all__' # 这里的__all__只会包含模型定义的字段,不影响我们手动添加的额外字段 def __init__(self, *args, **kwargs): # 先调用父类的__init__,确保模型对应的字段已经初始化完成 super(ExampleForm, self).__init__(*args, **kwargs) # 运行时动态获取选项,比如从其他模型查询数据 dynamic_choices = [(obj.id, obj.display_name) for obj in SomeOtherModel.objects.all()] # 给表单添加新的ChoiceField self.fields['stuff'] = forms.ChoiceField( choices=dynamic_choices, required=True, # 根据业务需求设置是否必填 label='动态选择项' )
进阶:根据表单实例动态调整选项
如果是编辑场景,需要根据当前表单绑定的实例来过滤选项,我们可以先取出instance参数再做处理:
def __init__(self, *args, **kwargs): # 先取出instance(如果有的话),再调用父类初始化方法 instance = kwargs.get('instance') super(ExampleForm, self).__init__(*args, **kwargs) # 根据实例动态生成选项 if instance: # 比如只显示和当前实例关联的选项 dynamic_choices = [(obj.id, obj.display_name) for obj in SomeOtherModel.objects.filter(related_instance=instance)] else: # 新增场景下显示所有选项 dynamic_choices = [(obj.id, obj.display_name) for obj in SomeOtherModel.objects.all()] self.fields['stuff'] = forms.ChoiceField( choices=dynamic_choices, required=True, label='关联选择项' )
扩展:其他字段类型的动态添加
这种方法不止适用于ChoiceField,任何表单字段类型都可以动态添加。比如要加一个带动态初始值的CharField:
def __init__(self, *args, **kwargs): super(ExampleForm, self).__init__(*args, **kwargs) # 动态生成初始值 dynamic_initial = "根据运行时逻辑生成的初始文本" self.fields['extra_text'] = forms.CharField( initial=dynamic_initial, required=False, label='额外文本字段' )
注意事项
- 一定要先调用父类的
__init__方法,否则self.fields还未初始化,直接操作会报错。 - 动态添加的字段和模型字段完全等价,渲染表单时会正常显示,提交后也能通过
cleaned_data['字段名']获取对应的值。
内容的提问来源于stack exchange,提问作者FabioCosta
相关产品推荐
相关产品推荐

