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)