在James Bennett的文章"So you want a dynamic form"(2008年11月9日)中,他写道,要创建一个动态表单,你可以做这样的事情:
def make_contact_form(user):
fields = { 'name': forms.CharField(max_length=50),
'email': forms.EmailField(),
'message': forms.CharField(widget=forms.Textarea) }
if not user.is_authenticated():
fields['captcha'] = CaptchaField()
return type('ContactForm', (forms.BaseForm,), { 'base_fields': fields })
但是你如何用forms.ModelForm
做同样的事情?
到目前为止,我只是在做这样的事情(我无法弄清楚如何将type
与内部类'Meta'一起使用)
def make_order_edit_form(include_fields):
class _OrderEditForm(forms.ModelForm):
if 'fa_date' in include_fields:
fa_date = CustomDateTimeField(label="first appointment time")
class Meta:
model = Order
fields = include_fields
widgets = custom_widgets
return _OrderEditForm
其中include_fields
是我要显示的字段元组。
但即使我写了正确的make_order_edit_form
,我如何在views.py
中使用它?具体来说,我如何将POST请求和订单实例都传递给它?通常我会做类似
order = Order.objects.get(pk=pk)
order_form = OrderEditForm(data=request.POST, instance=order)
加分问题:
为什么Bennett会从ContactForm
而不是forms.BaseForm
创建forms.Form
? (我假设这就是为什么这些字段也被称为base_fields
。)
答案 0 :(得分:3)
make_order_edit_form
会返回ModelForm
类,因此您可以
form_cls = make_order_edit_form(fields)
order_form = form_cls(request.POST, instance=order)
对于红利问题,请查看Form
代码:
class Form(BaseForm):
"A collection of Fields, plus their associated data."
# This is a separate class from BaseForm in order to abstract the way
# self.fields is specified. This class (Form) is the one that does the
# fancy metaclass stuff purely for the semantic sugar -- it allows one
# to define a form using declarative syntax.
# BaseForm itself has no way of designating self.fields.
__metaclass__ = DeclarativeFieldsMetaclass
Form
有一个自定义的元类DeclarativeFieldsMetaclass
,它会自动收集以声明性语法编写的表单字段,如果您在Form
中使用type()
,它看起来像是(采取Bennett& #39; s例子)
type('ContactForm', (forms.Form,), {
'name': forms.CharField(max_length=50),
'email': forms.EmailField(),
'message': forms.CharField(widget=forms.Textarea)}
# instead of
type('ContactForm', (forms.BaseForm,), { 'base_fields': fields })
更新
使用ModelForm
构建type
,没有太多不同
def make_order_edit_form(include_fields):
d = {}
class Meta:
model = Order
fields = include_fields
widgets = custom_widgets
d = {'Meta':Meta}
if 'fa_date' in include_fields:
d['fa_date'] = CustomDateTimeField(label="first appointment time")
return type('OrderEditForm', (forms.ModelForm,), d)