我目前正在 Pyramid 中的某个项目上工作,并且对wtforms SelectField有问题。
我有3个SelectField字段:
我可以在 View 中加载的car_make选项。剩下的选择域(Car_Model,Car_Version)的选择我将通过Ajax/JavaScript加载客户端(我可以在选择Car_Make等时选择Car_Model)。
问题是,当我提交表单时,car_model和car_version会引发“无效选择”,因为(在SelectField.pre_validation行431中)self.choices为空。
我该如何解决这个问题?
最佳答案
您要执行的操作是让WTForms处理“级联选择”(一种选择的有效字段由另一种字段的值确定)。使用内置字段确实不是一个好方法。
WTForms中的SelectField不能为您提供一个选项,例如“不验证所提供的选择是否有效”。您必须提供选择,以便字段验证选择。
与shown in the docs一样,虽然通常可以用静态的选项列表填充options字段。
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”的选择将动态填充到您的 Pyramid View 中。因此,这就是您需要做的:您需要填写 View 中的选择。这是解决
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...
您可能需要稍微调整一下才能使其完全按照您想要的方式工作,但我还没有实际测试过这种方法是否可行。