Can I set a StringField's default value outside the field constructor?
Asked Answered
O

3

2

If I set the default value during construction of the field, all works as expected:

my_field = StringField("My Field: ", default="default value", validators=[Optional(), Length(0, 255)])

However, if I try to set it programmatically, it has no effect. I've tried by modifying the __init__ method like so:

class MyForm(FlaskForm):
    my_field = StringField("My Field: ", validators=[Optional(), Length(0, 255)])

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.my_field.default = "set default from init"  # doesn't work

This does not set the default value. How can I do this programatically (because the value is dynamic based on a database query, and if I do this outside of __init__ then it does not get the most current value)?

Relevant versions from my requirements.txt:

Flask==0.12
Flask-WTF==0.14.2
WTForms==2.1

Also, I'm running Python 3.6 if that matters.

Alternatively, I'm fine with a solution that enables me to set the value data for this field on initial form load when adding a new record (same behavior as default value being specified in constructor) but this same form is also used for editing so I would not want it changing object data that is already saved/stored on edit.

Ornelas answered 29/7, 2018 at 3:22 Comment(5)
Do you want to do something like this? https://mcmap.net/q/1020912/-flask-wtforms-autofill-stringfield-with-variableAstrix
@Astrix I think so but that seems like a slightly different situation as it seems to have two different forms (NewForm and Foo), whereas I have only one form but just want to set a default value dynamically for one field. Will see if I can get it working and let you know.Ornelas
@Astrix turns out that is pretty much exactly what I needed! Was easy to implement/apply. I just upvoted it but would also upvote and accept as answer if posted/contextualized here. Thanks!Ornelas
@Astrix out of curiosity, can that also be used to set a selectfield default value where choices are populated dynamically in the form's init method?Ornelas
Answer posted. I had a quick look at setting choices ion the selectfield, seemed to work if I set form.field.choices after creating the form, but not if I did it inside the form's __init__ method. Perhaps you could ask a separate question for this, showing how you're populating the choices? Thanks for spotting the Foo typo in the other answer.Astrix
A
5

You can set initial values for fields by passing a MultiDict as FlaskForm's formdata argument.

from werkzeug.datastructures import MultiDict

class MyForm(FlaskForm):
    my_field = StringField("My Field: ", validators=[Optional(), Length(0, 255)])


form = MyForm(formdata=MultiDict({'my_field': 'Foo}))

This will set the value of the my_field input to 'Foo' when the form is rendered, overriding the default value for the field. However you don't want to override the values when the form is posted back to the server, so you need to check the request method in your handler:

from flask import render_template, request
from werkzeug.datastructures import MultiDict

@app.route('/', methods=['GET', 'POST'])
def test():
    if request.method == 'GET':
        form = MyForm(formdata=MultiDict({'my_field': 'Foo'}))
    else:
        form = MyForm()
    if form.validate_on_submit():
        # do stuff
    return render_template(template, form=form)
Astrix answered 31/7, 2018 at 6:3 Comment(0)
P
1

its to late to reply on this question but I saw a simple way to do this which is not mentioned in answers above. Simplest way to asign a value is

@app.route('/xyz', methods=['GET', 'POST'])
def methodName():
    form = MyForm()
    form.field.data = <default_value>
    .....
    return render_template('abc.html', form=form)

The field of the form will display asigned default_value when page load.

Planksheer answered 12/3, 2020 at 19:28 Comment(0)
I
0

You can access your fields in __init__ as a dictionary:

class MyForm(FlaskForm):

  def __init__(self, *args, **kwargs):
     default_value = kwargs.pop('default_value')
     super(MyForm, self).__init__(*args, **kwargs)
     self['my_field'] = StringField("My Field: ", default=default_value,
                                    validators=[Optional(), Length(0, 255)])

You would then call it like this:

form = MyForm(default_value='Foo')

See the documentation for the wtforms.form.Form class for more information and other details.

Iatrochemistry answered 29/7, 2018 at 3:36 Comment(2)
This doesn't work. It says, "TypeError: Fields may not be added to Form instances, only classes." But perhaps I misunderstood as I declared the field in the previous scope and then redefined -- are only defining it when you get a default arg (I need this field to be present no matter what - the same form is used for add/edit but default should only be populated on add which is standard behavior)? I'd be happy with a means to simply populate the value data only when the form is being used to add a new record as well - I don't have to use default constructor option.Ornelas
This answer is still setting it using the constructor, which is what I'm trying to avoid. I want to construct the field and set its default after doing so, or at least update it's value data on initial form load if a blank form (no obj populated, i.e. adding a new record). Also, I won't always be passing that keyword, in which case this will throw a KeyError.Ornelas

© 2022 - 2024 — McMap. All rights reserved.