Home > database >  How do I pre-fill a Flask WTForms Form with existing data for an "Edit Profile" route?
How do I pre-fill a Flask WTForms Form with existing data for an "Edit Profile" route?

Time:10-12

The problem

Whenever I write data to the attribute form.[any-field-name].data, the written data appears in the form, which is what I want. However, if a change is made in the form field when the form is rendered, the new value seems to only be stored in form.[any-field-name].raw_data. form.[any-field-name].data merely shows the original value that was written to .data before the user had the chance to type a new value in the field.

Obviously I could just grab the results from .raw_data, but that would defeat the purpose of having a form validation library. How can I elegantly pre-fill form fields for the user while allowing Flask-WTForms to accept fresh data from those same fields?

FYI: This is a bit different from a typical "edit profile" route, as my app creates a new UserVersion record every time a profile edit is made.

The Flask route

@app.route("/edit_user", methods=["GET", "POST"])
@login_required
def edit_user_self():
    """Edit user account that is currently logged in."""

    # get latest version of currently logged in user
    user_version = current_user.user_versions[0]

    # instantiate form and fill with existing data
    form = EditUserForm()
    form.username.data = user_version.username
    form.email.data = user_version.email
    form.addr_housenumber.data = user_version.addr_housenumber
    form.addr_street.data = user_version.addr_street
    form.addr_unit.data = user_version.addr_unit
    form.addr_city.data = user_version.addr_city
    form.addr_state.data = user_version.addr_state
    form.addr_postcode.data = user_version.addr_postcode

    if not form.validate_on_submit():
        return render_template("edit_user.html", form=form)
    else:
        # create new user version
        new_user_version = UserVersion(user=current_user,
            username = form.username.data,
            password = user_version.password,
            email = form.email.data,
            addr_housenumber = form.addr_housenumber.data,
            addr_street = form.addr_street.data,
            addr_unit = form.addr_unit.data,
            addr_city = form.addr_city.data,
            addr_state = form.addr_state.data,
            addr_postcode = form.addr_postcode.data
        )

        db.session.add(new_user_version)
        db.session.commit()

        flash("Changes saved")
        return redirect("/view_user")

The form model

class EditUserForm(FlaskForm):
    username = StringField(
        "Username", validators=[DataRequired(message="Please enter a username")]
    )
    email = StringField(
        "Email",
        validators=[
            DataRequired(),
            Email(message="Please enter a valid email address"),
        ],
    )
    addr_housenumber = StringField("Housenumber", validators=[Length(max=80)])
    addr_housename = StringField("Housename", validators=[Length(max=80)])
    addr_conscriptionnumber = StringField(
        "Conscription Number", validators=[Length(max=80)]
    )
    addr_street = StringField("Street", validators=[Length(max=80)])
    addr_place = StringField("Place", validators=[Length(max=80)])
    addr_postcode = StringField("Postcode", validators=[Length(max=80)])
    addr_city = StringField("City", validators=[Length(max=80)])
    addr_country = StringField("Country", validators=[Length(max=80)])
    addr_hamlet = StringField("Hamlet", validators=[Length(max=80)])
    addr_suburb = StringField("Suburb", validators=[Length(max=80)])
    addr_subdistrict = StringField("Subdistrict", validators=[Length(max=80)])
    addr_province = StringField("Province", validators=[Length(max=80)])
    addr_state = StringField("State", validators=[Length(max=80)])
    addr_door = StringField("Door", validators=[Length(max=80)])
    addr_unit = StringField("Unit", validators=[Length(max=80)])
    addr_floor = StringField("Floor", validators=[Length(max=80)])
    addr_block = StringField("Block", validators=[Length(max=80)])
    submit = SubmitField("Save")

Library versions

  • Flask 1.1.2
  • Flask WTForms 0.14.3
  • Flask SQLAlchemy 2.1

CodePudding user response:

I use placeholder for this purpose. You can pre-fill in the edit_user_self by mean of:

form.username.render_kw({'placeholder':user_version.email})

Oterwise you can do it in jinja like this:

{{wtf.form_field(form.email,
 placeholder=user_version.email)}}

but to do so you should pass additional information to jinja template.

CodePudding user response:

You need to swap your logic around. Test for form submission and validate first, else pre-populate and return the form:

@app.route('/submit', methods=['GET', 'POST'])
def submit():
    form = MyForm()
    
    if form.validate_on_submit():
        #Validate and Process submitted form first:
        new_user_version = UserVersion(user=current_user,
                                       username = form.username.data)

        db.session.add(new_user_version)
        db.session.commit()
        return redirect('/success')

    user_version = current_user.user_versions[0]
    #Pre-populate your form here:
    form.username.data = user_version.username

    return render_template('submit.html', form=form)
  • Related