1

Question:

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.

Related Code Examples:

  • 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.')
  • I can't find anything in the View function that is causing the 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 %}

2 Answers2

1

Just insert simple if logic.

if form.firstname.data:
    current_user.firstname = form.firstname.data
if form.lastname.data:
    current_user.lastname = form.lastname.data

If the user cannot edit/change the username why are you creating that as an editable field? It would be better to have that as a hidden field and pass the data.

It seems to me that your form is inconsistent. Why auto populate some fields and not others?

If the user is new and you are collecting data for the first time then all fields should be blank and editable.

If the form to edit details then all fields should be auto populated and username should be hidden since you said he can't change it.

Attack68
  • 4,437
  • 1
  • 20
  • 40
0

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!