I'm working on a Flask app w/ a WTForms EditProfileForm containing: First Name, Last Name, Username, and About Me. The form loads w/ Username and About Me auto-populated. First Name and Last Name are blank. If the user edits the About Me TextAreaField, but leaves the First Name and Last Name fields blank, submitting the form overwrites those DB fields as blank.
In the following forms.py code example, I had validators=[DataRequired()])
on firstname
and lastname
, but since those fields were showing up blank, it was requiring the user to re-enter their first and last name any time they wanted to edit any field(s). So I removed those validator.
Also on first and last name there is a username validate function so that if the user does not change their Username, which must be unique, upon submission the query doesn't return the false-positive error that the username must be unique.
forms.py - EditProfileForm class:
class EditProfileForm(FlaskForm):
firstname = StringField('First Name')
lastname = StringField('Last Name')
username = StringField('Username', validators=[DataRequired()])
about_me = TextAreaField('About Me', validators=[Length(min=0, max=140)])
submit = SubmitField('Submit')
def __init__(self, original_username, *args, **kwargs):
super(EditProfileForm, self).__init__(*args, **kwargs)
self.original_username = original_username
def validate_username(self, username):
if username.data != self.original_username:
user = User.query.filter_by(username=self.username.data).first()
if user is not None:
raise ValidationError('Please choose a different username.')
firstname
and lastname
fields to appear blank but the username
and about_me
fields to auto-populate.routes.py - the edit_profile view
@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
form = EditProfileForm(current_user.username)
if form.validate_on_submit():
current_user.firstname = form.firstname.data
current_user.lastname = form.lastname.data
current_user.username = form.username.data
current_user.about_me = form.about_me.data
db.session.commit()
flash(_('Your changes have been saved.'))
return redirect(url_for('edit_profile'))
elif request.method == 'GET':
form.username.data = current_user.firstname
form.username.data = current_user.lastname
form.username.data = current_user.username
form.about_me.data = current_user.about_me
return render_template('edit_profile.html', title=_('Edit Profile'),
form=form)
models.py - the User class
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(50), index=True)
lastname = db.Column(db.String(50), index=True)
username = db.Column(db.String(50), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
about_me = db.Column(db.String(140))
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
edit_profile.html
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Edit Profile</h1>
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}
Turns out, the problem was a simple copy/paste error that I made in the routes.py edit_profile view function. I had this...
form.username.data = current_user.firstname
form.username.data = current_user.lastname
form.username.data = current_user.username
form.about_me.data = current_user.about_me
I had form.username.data
in three out of the four field. Doh!