rje
rje

Reputation: 6418

flask-wtf editing a model using wtform Form constructor: pre-filling the form

I am reading the Flask Web Development book and came across this:

def edit_profile():
    form = EditProfileForm()
    if form.validate_on_submit():
        current_user.name = form.name.data
        current_user.location = form.location.data
        current_user.about_me = form.about_me.data
        db.session.add(user)
        flash('Your profile has been updated.')
        return redirect(url_for('.user', username=current_user.username))
    form.name.data = current_user.name
    form.location.data = current_user.location
    form.about_me.data = current_user.about_me
    return render_template('edit_profile.html', form=form)

Basically, when the form is not posted or doesn't validate, this copies over the data from the current user. Now reading up on wtforms, I read this about the init method on a form:

obj – If formdata is empty or not provided, this object is checked for attributes
      matching form field names, which will be used for field values.

So I guess that means that we could write this (the sample below is my own):

def edit_post(post_id):
    post = Post.query.get_or_404(post_id)
    if current_user != post.author:
        abort(403)
    # Below is the line I am concerned about
    form = PostForm(formdata=request.form, obj=post)
    if form.validate_on_submit():
        form.populate_obj(post)
        db.session.commit()
        return redirect(url_for('user', username=current_user.username))
    return render_template('post_form.html', form=form)

I figure that this should fill the form instance from the database model on GET, and from POST data after post. Testing this, it seems to work..

Now my question: is this way of writing an edit view correct? Or should I copy everything over field by field, like in the book?

Upvotes: 1

Views: 3706

Answers (1)

Timusan
Timusan

Reputation: 3435

Loading in a POST MultiDict is certainly the accepted way to map key/value pairs to your WTForms instance. Even more so, if you are using the Flask-WTF extension, this is automatically done for you, it is one of the perks that this extension brings you.

If you would crack open the code of Flask-WTF you would see that it inherits the SecureForm class of WTForms and tries to load in the Werkzeug POST MultiDict (called formdata) by default (if it is present). So loading in your form in your view like this:

form = PostForm(obj=post)

Should be sufficient (if using Flask-WTF) to also fill the fields with POSTed data.

The way it is done in your book example is certainly not wrong, but creates a lot of unnecessary code and is error prone / redundant - one could forget to mention a field in the view that is declared in the WTForms instance.

Upvotes: 1

Related Questions