Flask WTForms autofill StringField with variable
Asked Answered
T

1

2

I have a form that I want to automatically fill some of the fields with information received on a previous page, but it needs to be changeable if they want to adjust it. I am using a dynamically created list for my SelectField that works, but adding the StringField has been unsuccessful. See my code below:

forms.py

class get_vals(var):
    ...
    typs = var.p_typs
    p_name = var.p_name
    return typs,p_name

class NewForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired()])
    typ1 = SelectField('Type', validators=[Optional()])

    def __init__(self,var):
        super(NewForm,self).__init__()
        typs,p_name = get_vals(var)

        self.typ1.choices = typs
        self.name.default = p_name

Using:

self.name.default 

leaves my name form blank. If I use:

self.name.data

it puts the correct information in the form, however you cannot change the values and must use whatever it places in, which is not an option.

...
<form action="" method="post">
    {{ form.hidden_tag() }}
    <p>
        {{ form.name.label }}
        {{ form.name(size=24) }}
        {{ form.typ1.label }}
        {{ form.typ1() }}
    </p>
...

Is there a way to set the default value which a variable and have it changeable? Thanks

UPDATE If I set the field I am trying to update to None after running the Form that gets the name variable, I am able to change the variable without error. However, it won't overwrite the form.name.data value

form = NewForm(var)
    var.name == None
    if form.validate_on_submit():
        var.name = form.name.data

This runs (displays correct variable in form and is adjustable) but doesn't overwrite the value when you submit the form, how can I overwrite the value?

Tackle answered 23/7, 2018 at 16:43 Comment(0)
S
2

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

from werkzeug.datastructures import MultiDict

form = NewForm(formdata=MultiDict({'name': 'Foo'}))

This will set the value of the name 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 hello():
    if request.method == 'GET':
        form = NewForm(formdata=MultiDict({'name': 'foo'}))
    else:
        form = NewForm()
    if form.validate_on_submit():
        # do stuff
    return render_template(template, form=form)

* A MultiDict is required because in an HTML form there may be multiple inputs with the same name attribute, and a MultiDict has methods that handle lists of values as well as single values like a normal dict.

Starrstarred answered 29/7, 2018 at 10:4 Comment(6)
When I attempt this solution, I get: TypeError: __init__() got an unexpected keyword argument 'formdata'Maker
@Maker are you using definitely using a FlaskForm? What version of wtf_flask?Starrstarred
yes, my example is just like the original question using class NewForm(FlaskForm). As for version: In [3]: flask_wtf.__version__ Out[3]: '0.14.2'Maker
Odd - the docs clearly show formdata is an acceptable keyword. Maybe you could whip up an minimal reproducible example and open a new question? Can't look now (at work) but maybe later/tomorrow.Starrstarred
Found my error, it works. It appears that the MultiDict does not work for updatingSelectField objects, from what I've observed so far.Maker
You could skip the MultiDict by simply doing form.name.data = "foo" in the if.Trafficator

© 2022 - 2024 — McMap. All rights reserved.