在wtforms中选择SelectField并通过javascript </option>添加<option>

时间:2013-12-31 11:47:26

标签: python pyramid wtforms

我目前正在处理金字塔中的某个项目,并且遇到wtforms SelectField问题。

我有3个SelectField字段:

  • car_make(例如“audi”)
  • car_model(例如,“audi 80”)
  • car_version(例如,“AUDI 80 B4”)。

我可以在视图中加载car_make选项。其余SelectFields(car_model,car_version)的选择我将通过AJAX / javascript加载到客户端(我可以在选择car_make时选择car_model等等。)

问题在于,当我提交表单时,car_model和car_version会引发“无效选择”,因为(在SelectField.pre_validation第431行中)self.choices为空。

如何解决这个问题?

1 个答案:

答案 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...

您可能需要稍微调整一下以使其按照您想要的方式工作,我实际上并没有测试过这种方法。