【问题标题】:How do you set a default value for a WTForms SelectField?如何为 WTForms SelectField 设置默认值?
【发布时间】:2012-08-19 10:44:47
【问题描述】:

当尝试使用 WTForms 设置 SelectField 的默认值时,我将值传递给 'default' 参数,如下所示。

class TestForm(Form):
  test_field = SelectField("Test: ", choices=[(1, "Abc"), (2, "Def")], default=2)

我也尝试了以下方法。

class TestForm(Form):
  test_field = SelectField("Test: ", choices=[(1, "Abc"), (2, "Def")], default=(2, "Def"))

既不将默认选定字段设置为“Def”。这适用于其他类型的字段,例如 TextField。如何设置 SelectField 的默认值?'

【问题讨论】:

    标签: python flask wtforms


    【解决方案1】:

    我相信这个问题是由Fielddata 属性用WTForms 不理解的东西覆盖default 引起的(例如,一个DB 模型对象——它需要一个int)。如果您像这样在构造函数中填充表单,就会发生这种情况:

    form = PostForm(obj=post)
    

    解决方案是在表单被填充后手动设置data 属性:

    form = PostForm(obj=post)
    form.category.data = (post.category.id
                          if page.category
                          else 0) # I make 0 my default
    

    【讨论】:

    • 在运行时从视图动态填充选项时,这是使其默认选择一个选项的正确方法。由于谷歌为这个问题带来了很多人,这应该是公认的答案。
    • 好吧,我注意到,当我将默认选项更改为视图列表中的另一个选项并提交表单时,会提交默认选项而不是新选项。如何解决这个问题?
    • 这似乎不再起作用了。当我更新该字段时,无论如何都会调用原始的choices=choicesfunction()。所以更新字段没有效果。 ** 更新 ** form.category.choices = [(),()] 为我工作
    【解决方案2】:

    您发布的第一种方式是正确的,它对我有用。它不起作用的唯一解释可能是您运行的是旧版本的 WTForms,它在 1.0.1 上对我有用

    【讨论】:

    • 请注意,对于SelectMultipleField,默认必须是一个列表,即:default=[2]
    【解决方案3】:

    Flask-WTF 0.14.2 用户在这里。所以这个答案适用于和我有类似问题的人。

    基本上,以前的解决方案都不能与form.validate_on_submit() 一起正常工作。

    设置form.test_field.data确实会在页面加载时改变默认值,但validate_on_submit之后的数据保持不变(用户在浏览器中更改没有效果)。

    设置form.test_field.default然后调用form.process()也会在页面加载时改变值,但是validate_on_submit会失败。

    这是一种新的方法:

    class TestForm(Form):
        test_field = SelectField("Test", choices=[(0, "test0"), (1, "test1")])
    
    @app.route("/test")
    def view_function():
        form = TestForm(test_field=1)
        if form.validate_on_submit():
            ...
    

    【讨论】:

    • 是的。这是有效的。换一种说法:要在选择列表中选择特定选项,该选项必须在第一次实例化时加载到表单中。同样,要在多选列表中选择多个选项,必须在第一次实例化时将选项加载到表单中。设置选择列表的语法取决于它是什么类型:1) 选择列表示例:form = MyUserForm(roles=1) #第一个选项是预先选择的 2) selectmultiplelist 示例:form = MyUserForm(roles=[1,3]) #第一个和第三个选项是预选的
    • 也适合我! Flask-WTF == 0.14.3
    【解决方案4】:

    有几种方法可以做到这一点。你的第一个代码 sn-p 确实是正确的。

    如果您想在视图中动态执行此操作,您也可以这样做:

    form = TestForm()
    form.test_field.default = some_default_id
    form.process()
    

    【讨论】:

    • 非常感谢,我在文档中都找不到解决方案,非常感谢
    【解决方案5】:

    这是一个choices 设置与SelectField,当您使用int 时,它的工作原理如下:

    test_select = SelectField("Test", coerce=int, choices=[(0, "test0"), (1, "test1")], default=1)
    

    或:

    class TestForm(Form):
        test_select = SelectField("Test", coerce=int)
    
    @app.route("/test")
    def view_function():
        form = TestForm()
        form.test_select.choices = [(0, "test0"), (1, "test1")]
        form.test_select.default = 1
        form.process()
    

    【讨论】:

    • 你测试过第二个变种吗?调用 `form.test_select.default = 1` 不会改变我系统上的任何内容。
    • 使用整数 ID 时的 coerce=int 是一项重要设置。在两种形式上设置默认值,一种有效,另一种无效。原来一个 ID 是一个字符串,另一个是一个整数。强制解决了问题。
    • 第二个工作正常,但您必须编辑一些内容。正确的语法是form.test_select.process([])。 process 方法需要一个 iterate 参数。我测试的版本是2.3.1。
    【解决方案6】:

    如果您正在使用 flask_wtf 并希望为嵌套在这样的 FieldList 中的不同 SelectFields 设置默认值

    from flask_wtf import FlaskForm
    
    
    class FormWithSelect(FlaskForm):
        my_select_field = SelectField(validators=[DataRequired()], coerce=int)
    
    
    class FormWithMultipleSelects(FlaskForm):
        select_fields = FieldList(FormField(FormWithSelect), min_entries=1)
        submit = SubmitField(label="save all the select field values")
    

    解决方案是覆盖data,而不是您所期望的default

    def generate_my_form(my_data, overwrite_data=True):
        form = FormWithMultipleSelects(select_fields=[{
            "my_select_field": {
                 "name": d["name"],
                 # ...
            }
        } for d in my_data]))
        for n range(len(form.select_fields)):
            form.select_fields[n].my_select_field.choices = [(1,'foo'), (2,'bar')]
            # I wan't 'bar' to be the option selected by default
            # form.select_fields[n].my_select_field.default = 2  # has no effect!
            if overwrite_data:
                form.select_fields[n].my_select_field.data = 2 #  works
    

    这个方案基本上和上面的Elliots answer类似;我只是想为更复杂的 FieldList 案例提供解决方案。 nikitz 在评论中提到,有一个副作用:form.validate_on_submit() 如果你覆盖 data 将不起作用!您可以构建一个简单的解决方法,在调用validate_on_submit() 时禁用data 的覆盖。

     form_for_validation = generate_my_form(my_data, False)
     if form_for_validation.validate_on_submit():
          # do something with form_for_validation.data
     else:
         form_with_default_data = generate_my_form(my_data, True)
         render_template(..., form=form_with_default_data)
    

    它不是超级优雅,但它确实有效。

    PS:我的声誉太低,无法直接评论 Elliot 的正确答案。

    【讨论】:

    • 这篇文章的三分之二听起来像是一个问题,而不是一个答案。能不能把开头写“The solution was...”后面的部分,如果觉得有帮助,后面再提供背景?
    【解决方案7】:

    我对动态设置默认选择字段有一些问题,我认为这很有用。 模型是这样的:

    class State(db.Model):
        __tablename__ = 'states'
        id = db.Column(db.Integer, primary_key=True)   
        name = db.Column(db.String(128), nullable=False)
    
    
    class City(db.Model):
        __tablename__ = 'cities'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(64))
        state_id = db.Column(db.Integer, db.ForeignKey('states.id'))   
        state = db.relationship(State, backref='state')
    
    
    class User(UserMixin, db.Model):
        ...
        city_id = db.Column(db.Integer, db.ForeignKey('cities.id'))
        city = db.relationship('City', backref='city')
    

    表格是这样的:

    class UserEditForm(FlaskForm):
        ...
        state = SelectField("state", coerce=int)
        city = SelectField("city", coerce=int)
        ....
    
      def __init__(self, state_id, *args, **kwargs):
           super(UserEditForm, self).__init__(*args, **kwargs)
           self.state.choices =  [(state.id, state.name)
                            for state in State.query.order_by('name').all()]
           self.city.choices = [(city.id, city.name)
                                for city in   City.query.filter_by(state_id=state_id).order_by('name').all()]   
    

    视图是这样的:

    @dashboard.route('/useredit', methods=['GET', 'POST'])
    @login_required
    def useredit():
        ....
        user = current_user._get_current_object()       
        form = OrganEditForm(state_id=user.city.state_id, state=user.city.state_id, city=user.city_id)
         ....
    

    它运行良好并正确设置 Selectfield 默认值。但我改变了这样的代码:

    在视图中:

    @dashboard.route('/useredit', methods=['GET', 'POST'])
        @login_required
        def useredit():
            ....
            user = current_user._get_current_object()       
            form = OrganEditForm(obj=user)
             ....
    

    在表格中

    def __init__(self, *args, **kwargs):
           super(UserEditForm, self).__init__(*args, **kwargs)
           self.state.choices =  [(state.id, state.name)
                            for state in State.query.order_by('name').all()]
           self.city.choices = [(city.id, city.name)
                                for city in   City.query.filter_by(state_id=kwargs['obj'].city.state_id).order_by('name').all()] 
    

    但是这次没有设置城市默认值。我改变了这样的形式:

    def __init__(self, *args, **kwargs):
               kwargs['city'] = kwargs['obj'].city_id
               super(UserEditForm, self).__init__(*args, **kwargs)
               self.state.choices =  [(state.id, state.name)
                                for state in State.query.order_by('name').all()]
               self.city.choices = [(city.id, city.name)
                                    for city in   City.query.filter_by(state_id=kwargs['obj'].city.state_id).order_by('name').all()] 
    

    但它没有用。我尝试了很多解决方案,最后我将城市变量名称更改为 usercity:

    usercity= SelectField("city", coerce=int)
    

    kwargs['city'] = kwargs['obj'].city_idkwargs['usercity'] = kwargs['obj'].city_id。在它正常工作之后。

    问题是当我设置obj=user 时,城市选择字段的默认值从kwargs['obj'].city 读取,我在user 模型中定义。

    【讨论】:

      【解决方案8】:
      Python Flask SelectField choices 
      
          # method 1 - routes.py
           form.proj_cat_id.default    = table1.proj_cat_id
           form.process()  # for preset 
      
          # method 2 - routes.py
          form.proj_cat_id.process_formdata([table1.proj_cat_id])
      
      
      
      # method 3  - routes.py
            proj_cat_id_default    = table1.proj_cat_id
            return render_template('abc.html',proj_cat_id_default=proj_cat_id_default)
      
      # method 3 - abc.html
              {% set z = form.proj_cat_id.process_data(proj_cat_id_default) %}
              {{ form.proj_cat_id(class="form-control form-control-lg") }}
      

      【讨论】:

        猜你喜欢
        • 2021-04-07
        • 2016-07-09
        • 2020-12-14
        • 2019-02-21
        • 2014-03-02
        • 1970-01-01
        • 2022-12-04
        • 2015-10-04
        • 1970-01-01
        相关资源
        最近更新 更多