David
David

Reputation: 2620

Python Flask-WTF - use same form template for add and edit operations

I'm just getting started with Flask / Flask-WTF / SQLAlchemy, and most example CRUD code I see shows separate templates for adding / editing. It seems repetitive to have two templates with almost identical form html (e.g. books_add.html, books_edit.html). Conceptually it makes more sense to me to have one template, something like "books_form.html", and just call render_template on that same template from two separate route definitions. I'm not quite sure how to accomplish it though, something like:

@app.route('/books/add')
def add_book():
...
render_template('books_form.html', action = 'add')


@app.route('/books/edit/<id>')
def edit_book(id):
...
render_template('books_form.html', action = 'edit', id = id)

but I'm not sure if I'm on the right track, or deviating from best practice. Any input is appreciated - specific thoughts on how to handle the single template file to deal with either add or edit behavior. Links to examples are welcome as well.

Thanks!

Upvotes: 16

Views: 15970

Answers (2)

Michael Elimu
Michael Elimu

Reputation: 71

The simplest way I tried to overcome this issue was to not include the SubmitField in the form (BookForm). We can pass the form submit value as variable to the form, e.g submit='Update' in the edit_book route and submit='Add Book'.

In the route, populate the fields with the details related to the book if the post method is 'GET'

Upvotes: 1

Sean Vieira
Sean Vieira

Reputation: 159865

There is absolutely no reason to have separate templates for adding / editing different kinds of things even. Consider:

{# data.html #}
<!-- ... snip ... -->
{% block form %}
<section>
<h1>{{ action }} {{ data_type }}</h1>
<form action="{{ form_action }}" method="{{ method | d("POST") }}">
{% render_form(form) %}
</form>
</section>
{% endblock form %}

Ignore the macro render_form works (there's an example one in WTForms' documentation) - it just takes a WTForms-type object and renders the form in an unordered list. You can then do this:

@app.route("/books/")
def add_book():
    form = BookForm()
    # ... snip ...
    return render_template("data.html", action="Add", data_type="a book", form=form)

@app.route("/books/<int:book_id>")
def edit_book(book_id):
    book = lookup_book_by_id(book_id)
    form = BookForm(obj=book)
    # ... snip ...
    return render_template("data.html", data_type=book.title, action="Edit", form=form)

But you don't need to limit yourself to just books:

@app.route("/a-resource/")
def add_resource():
    # ... snip ...
    return render_template("data.html", data_type="a resource" ...)

# ... etc. ...

Upvotes: 20

Related Questions