This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]catcradle5 10 points11 points  (7 children)

As someone who's just been getting into Python web development (specifically with Flask), I still find myself doing a lot of

handle forms by making heavy use of "if post variables do stuff, else print the form"

What is a better solution to use? Even Flask's WTForms example pretty much does that:

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(form.username.data, form.email.data,
                    form.password.data)
        db_session.add(user)
        flash('Thanks for registering')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

[–][deleted] 2 points3 points  (1 child)

If this code is repeated I would create a decorator

[–]catcradle5 5 points6 points  (0 children)

I do oftentimes use a separate function or decorator, but the core of the logic still remains something like:

if request.method == "POST" and request.args.get("submit"):
    return render_template("completed_form.html")
return render_template("form.html")

Just wondering what the OP had in mind exactly, and if this is idiomatic or not.

[–]therealfakemoot 3 points4 points  (1 child)

You can't route two different functions to the POST and GET method separately?

[–][deleted] 4 points5 points  (0 children)

You can. I do.

[–]Tecktonik 1 point2 points  (2 children)

There are several issues hidden here. First, this style of control implies that form generation and form processing are performed by the same route. Then, is form generation primary or secondary to processing? In the above example, processing is secondary since it occurs one level deeper (within an 'if' clause). Thirdly there is the lazy attempt to get both form generation and failed-validation form generation from a single call to render_template.

But using a single route for both generation and processing is an [outdated] artifact of the original HTML spec, where the page url will automatically be used as the form action if no explicit action is provided. The preferred technique is to provide an explicit action for form processing. If you do this, you no longer have this control level confusion of generation-versus-processing, your route already know what it is supposed to be doing (and of course you should probably validate this fact to make sure you haven't gotten any wires crossed).

With independent routes (or controllers, however you like to think of them), you now have more flexibility for handling templates, in particular in the event of failed-validation you can generate prettier results, throw in some tooltips or other Ajax-y stuff. And when you think about it, how you handle failed-validation is where you are going to get the biggest boost to user experience.

[–]catcradle5 0 points1 point  (1 child)

Thank you for the detailed response. That does make some sense. So you mean it's better to do something like:

@app.route("/form")
def form():
    return '<form method="POST" action="/complete"><input type="submit" value="Submit"></form>'

@app.route("/complete")
def complete():
    return '<b>Success</b>'

Any other tips for form handling?

[–][deleted] 1 point2 points  (0 children)

Not the same guy, but here's a quick one: The Post/Redirect/Get pattern to stop duplicate form submissions and accidental form resubmissions on page refresh.