我目前正在处理金字塔中的某个项目,并且遇到wtforms SelectField问题。
我有3个SelectField字段:
我可以在视图中加载car_make选项。其余SelectFields(car_model,car_version)的选择我将通过AJAX / javascript加载到客户端(我可以在选择car_make时选择car_model等等。)
问题在于,当我提交表单时,car_model和car_version会引发“无效选择”,因为(在SelectField.pre_validation第431行中)self.choices为空。
如何解决这个问题?
答案 0 :(得分:11)
你要做的是让WTForms处理“级联选择”(具有一个选择的有效字段由另一个字段的值确定)。使用内置字段确实没有好办法。
WTForms中的SelectField没有为您提供“不验证所提供的选项是否有效”的选项。您必须提供选择,以便该字段验证选择。
作为shown in the docs,虽然您通常可以使用静态选项列表填充选项字段...
class PastebinEntry(Form):
language = SelectField(u'Programming Language', choices=[('cpp', 'C++'), ('py', 'Python'), ('text', 'Plain Text')])
...但是,由于您是动态提出选项,因此需要在实例化表单后设置choices
属性。
def edit_user(request, id):
user = User.query.get(id)
form = UserDetails(request.POST, obj=user)
form.group_id.choices = [(g.id, g.name) for g in Group.query.order_by('name')]
在上面的示例中,“group_id”的选项会在您的金字塔视图中动态填充。那么,这就是你需要做的事情:你需要在你的视图中填写选项。这是您使用car_make
解决问题的方法(虽然我认为您在问题中说car_make
没问题。)
但是,您遇到的问题是car_model
的有效选择无法确定,因为它们依赖于已经解析和验证的car_make
。 WTForms并不能很好地处理这个问题(至少使用SelectFields),因为它假定所有字段都应该立即验证。换句话说,为了生成car_model
的有效选项列表,首先需要验证car_make
的值,这对于SelectField如何工作是不可能轻易做到的。
我看到这样做的最好方法是创建一个扩展SelectField类型的新字段类型,但删除了验证:
class NonValidatingSelectField(SelectField):
def pre_validate(self, form):
pass
这种新类型会覆盖pre_validate,通常会进行检查以确定选项是否有效。
如果您将其用于car_model
,则不会再出现错误。但是,现在这意味着您的字段实际上并未经过验证!要解决此问题,您可以在表单上添加in-line validator ...
class MyForm(Form):
car_make = SelectField(u'Make', choices=[...])
car_model = NonValidatingSelectField(u'Model', choices=[])
def validate_car_model(self, field):
choices = query_for_valid_models(self.car_make.data)
# check that field.data is in choices...
您可能需要稍微调整一下以使其按照您想要的方式工作,我实际上并没有测试过这种方法。