Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Michael Kristiansen
Michael Kristiansen
21,554 Points

Update existing Posts in "Build a social Network with Flask". Has anyone built this functionality?

How would I proceed if I wanted to make this possible? Do I make it as a function on the class or in app.py?

Currently I'm thinking of making it in the app.py. But honestly, I have no idea.. I've found this in the docs but I'm not sure how I could use it.

@app.route('/edit/<int:post_id>', methods=('GET', 'POST'))
@login_required
def edit_post(post_id)
    edit = models.Post.select().where(models.Post.id == post_id)
    form = forms.PostForm()

How do I populate the existing form in post.html with the data?

2 Answers

Michael Kristiansen
Michael Kristiansen
21,554 Points
@app.route('/edit_post/<int:post_id>', methods=('GET', 'POST'))
@login_required
def edit_post(post_id):
    form = forms.PostForm()
    if form.validate_on_submit():
        new_content = form.content.data.strip()
        q = models.Post.update(content=new_content).where(models.Post.id == Post_id)
        q.execute()
        flash("Post updated", "success")
        return redirect(url_for('index'))
    return render_template('edit_post.html', form=form)

Figured out the update part. Just missing the part where the form i filled out with the old content when the editing is opened.

UPDATE June 5. 2345: Did it. In case anyone needs this:

@app.route('/edit_post/<int:post_id>', methods=('GET', 'POST'))
@login_required
def edit_post(post_id):
    edit = models.Post.select().where(models.Post.id == post_id).get()
    form = forms.PostForm(obj=edit)
    form.populate_obj(edit)
    if form.validate_on_submit():
        new_content = form.content.data.strip()
        new_finished = form.finished.data
        q = models.Post.update(content=new_content, finished=new_finished).where(models.Post.id == post_id)
        q.execute()
        flash("Post updated", "success")
        return redirect(url_for('index'))
    return render_template('edit_post.html', form=form)

Credits to: (flask-wtf-tricks)[https://goonan.io/flask-wtf-tricks/]

Thanks for sharing, Michael! Super helpful.

I found this line especially neat! form = forms.PostForm(obj=edit)

And it saves a ton of time trying to pre-populate this over and over again for however many fields you have: form.<field>.data = edit.<field>

I am, however, a bit lost as to what the form.populate_obj(edit) line does.

I did a bit of digging in the wtforms library.

def populate_obj(self,obj):
python
for name, field in iteritems(self._fields):
            field.populate_obj(obj, name)

I don't really understand what self._fields means, but I assume it's referencing the /fields/core.py as that's the only other place I could find populate_obj. We see in /fields/core.py:

    def populate_obj(self, obj, name):
        """
        Populates `obj.<name>` with the field's data.
        :note: This is a destructive operation. If `obj.<name>` already exists,
               it will be overridden. Use with caution.
        """
        setattr(obj, name, self.data)

So populate_obj iterates over each record (field) in a row (model instance) and calls setattr. But why do we need to call this before we get data out of our form?

I'm able to have users edit their records without this line. Is there any reason to keep it? What does it do?

https://github.com/wtforms/wtforms/blob/master/wtforms/form.py https://github.com/wtforms/wtforms/blob/master/wtforms/fields/core.py