1

I have a form that is used for composing and editing blog posts like this:

class EditorForm(FlaskForm):
    title = StringField('Title', validators=[DataRequired(), Length(min=1, max=250)])
    body = PageDownField('Body', validators=[DataRequired()])
    tags = SelectMultipleField('Tags', coerce=int)
    timestamp = DateTimeField('Timestamp')
    published = BooleanField('Publish?')
    update = BooleanField('Update Timestamp?')
    delete = SubmitField('Delete')
    submit = SubmitField('Save')

In my view I distinguish between editing existing posts and creating new ones. For existing posts, if they have associated tags, I want these to be highlighted in the SelectMultipleField on the form so the user can see them.

If these are highlighted and I want to remove the tags, I need to be able to unhighlight them and submit the form to do so.

Here are the relevant parts of my view as it stands now:

@app.route('/editor/<slug>', methods=['GET', 'POST'])
@app.route('/editor/', methods=['GET', 'POST'])
@login_required
def editor(slug=None):
    # old post or new post?
    if slug:
        post = Post.query.filter_by(slug=slug).first()
    else:
        post = Post()

    # populate form, blank for new post
    form = EditorForm(obj=post)
    
    # populate tags field
    form.tags.choices = [(tag.id, tag.tag) for tag in Tag.query.order_by('tag')]

    # declare list for tag highlights on GET
    if request.method == 'GET':
        form.tags.default = []

    # if post has linked tags, highlight them
    if post.tags:
        for tag in post.tags:
            if tag.id not in form.tags.default:
                form.tags.default.append(tag.id)
        form.process()

In fishing around other questions related to my issue, I have discovered that I can't directly use form.tags.data to highlight associated tags because this means user action on the form is ignored for that field, even though the right choices will be highlighted. This is why I am using form.tags.default.

form.tags.default seems to work for highlighting the correct tags, BUT form.process() wipes all the other fields filled out by form = EditorForm(obj=post).

So my question is: how can I populate my form with existing post data AND highlight the right tags in the same instance?

1 Answers1

1

I seem to have obtained the result I wanted with this issue. Part of my original problem was actually related to some code in the view that I didn't post in my question.

On if form.validate_on_submit():, I was appending the tags in form.tags.data (highlighted choices) to my post.tags. In cases where posts already had attached tags this meant that deselecting the defaults in the field was indeed emptying form.tags.data as desired, but post.tags still had the original data anyway, hence no change.

This was solved with the following:

# empty tags list then add highlighted choices
    post.tags = []
    for id in form.tags.data:
        t = Tag.query.filter_by(id=id).first()
        post.tags.append(t)

I also changed my code that populated the form to be simpler. I was wrong about needing to use default over data (and frankly I don't understand the difference between the two):

    # populate form, blank for new post
    form = EditorForm(obj=post)
    # populate tags field
    form.tags.choices = [(tag.id, tag.tag) for tag in Tag.query.order_by('tag')]
    # populate defaults only on GET otherwise user choice overidden
    if request.method == 'GET':
        # declare default (highlighted) tags list
        form.tags.data = []
        # if post has tags, highlight them
        if post.tags:
            for tag in post.tags:
                form.tags.data.append(tag.id)