Wtforms动态生成
Wtfforms dynamic generation
我有两个wtfform
class SportStartForm(Form):
ski = DateField(format='%d.%m.%Y')
kitesurfing = DateField(format='%d.%m.%Y')
windsurfing = DateField(format='%d.%m.%Y')
surfing = DateField(format='%d.%m.%Y')
class UpdateUserForm(Form):
sport_start_at = FormField(SportStartForm)
它工作正常,但我想动态生成一个这样的表单
class SportStartForm(Form):
def __new__(cls, **kwargs):
for s in SPORTS:
setattr(cls, s, DateField(format='%d.%m.%Y'))
return super(SportStartForm, cls).__new__(cls, **kwargs)
如果我这样做,我会在表单验证时遇到异常
for name, unbound_field in itertools.chain(fields, extra_fields):
TypeError: 'NoneType' object is not iterable
我在这里用关于 wtfforms 动态生成的标签研究了几个问题,但它对我不起作用。我错过了什么?
导致错误的基本问题是因为您覆盖了 __new__
然后调用了超级构造函数,因此您绕过了 Form.__init__
which passes a mapping of fields to BaseForm.__init__
。
但是 即使尝试符合此接口,也可能不会最终得到您想要的东西,而不是没有大量的工作。原因是 WTForms 在 Form
上使用元 class 来检查字段并缓存未绑定字段列表 在 你的 class 被实例化之前,并且输入处理在实例化时完成,这要求所有字段都已在该点声明。
按照 Solving Specific Problems 页面中的提示,您可以使用以下方法之一更安全地创建动态表单:
1.假设SPORTS在应用程序初始化后不会改变,我们可以简单地创建一个top-levelclass并在其上设置属性
class SportStartForm(Form):
pass
for s in SPORTS:
setattr(SportStartForm, s, DateField(format='%d.%m.%Y'))
2. 或者,如果 SPORTS 是可以改变的,并且由于某些用户规则而动态变化,则可以像上面的链接那样完成 in-view页面,或作为工厂:
def factory(sports):
# This form class is created in a local scope, so a new class object
# is made each time your factory is called
class SportStartForm(Form):
pass
for s in sports:
setattr(SportStartForm, s, DateField(format='%d.%m.%Y'))
return SportStartForm
工厂模型的用法可能类似于:
def view(request):
form_class = factory(['tennis', 'golf', 'windsurfing'])
form = form_class(request.form)
# etc, rest of view
我有两个wtfform
class SportStartForm(Form):
ski = DateField(format='%d.%m.%Y')
kitesurfing = DateField(format='%d.%m.%Y')
windsurfing = DateField(format='%d.%m.%Y')
surfing = DateField(format='%d.%m.%Y')
class UpdateUserForm(Form):
sport_start_at = FormField(SportStartForm)
它工作正常,但我想动态生成一个这样的表单
class SportStartForm(Form):
def __new__(cls, **kwargs):
for s in SPORTS:
setattr(cls, s, DateField(format='%d.%m.%Y'))
return super(SportStartForm, cls).__new__(cls, **kwargs)
如果我这样做,我会在表单验证时遇到异常
for name, unbound_field in itertools.chain(fields, extra_fields):
TypeError: 'NoneType' object is not iterable
我在这里用关于 wtfforms 动态生成的标签研究了几个问题,但它对我不起作用。我错过了什么?
导致错误的基本问题是因为您覆盖了 __new__
然后调用了超级构造函数,因此您绕过了 Form.__init__
which passes a mapping of fields to BaseForm.__init__
。
但是 即使尝试符合此接口,也可能不会最终得到您想要的东西,而不是没有大量的工作。原因是 WTForms 在 Form
上使用元 class 来检查字段并缓存未绑定字段列表 在 你的 class 被实例化之前,并且输入处理在实例化时完成,这要求所有字段都已在该点声明。
按照 Solving Specific Problems 页面中的提示,您可以使用以下方法之一更安全地创建动态表单:
1.假设SPORTS在应用程序初始化后不会改变,我们可以简单地创建一个top-levelclass并在其上设置属性
class SportStartForm(Form):
pass
for s in SPORTS:
setattr(SportStartForm, s, DateField(format='%d.%m.%Y'))
2. 或者,如果 SPORTS 是可以改变的,并且由于某些用户规则而动态变化,则可以像上面的链接那样完成 in-view页面,或作为工厂:
def factory(sports):
# This form class is created in a local scope, so a new class object
# is made each time your factory is called
class SportStartForm(Form):
pass
for s in sports:
setattr(SportStartForm, s, DateField(format='%d.%m.%Y'))
return SportStartForm
工厂模型的用法可能类似于:
def view(request):
form_class = factory(['tennis', 'golf', 'windsurfing'])
form = form_class(request.form)
# etc, rest of view