1

I'm struggling with a Flask App that gives me Bad Request on a form submission. I've been through the little bit of documentation from Flask and a number of SO pages. I'm sure there's something simple I'm missing.

In a nutshell, I've developed a template to receive the form called 'placeindex.html'. The form 'name' data all matches. If I change the name of 'placeindex.html' to 'index.html' it works fine, even though I'm pointing to the 'placeindex.html' file. Code below (view):

@app.route('/add_place', methods=['GET', 'POST'])
def add_place():
    username = session['username']
    placename = request.form['place']
    address = request.form['address']
    city = request.form['city']
    state = request.form['state']
    zipcode = request.form['zipcode']
    alias = request.form['alias']
    searchword = request.args.get('key', '')
    print(searchword)
    Place(session['username']).new_place(placename, address, city, state, zipcode, alias, username)
    return render_template('placeindex.html')

placeindex.html:

{% extends "layout.html" %}
{% block place %}

<h2>Home</h2>
  {% if session.username %}
    <h3>Add new 'placeindex'</h3>
            <form action="{{ url_for('add_place') }}" method="post">
            <dl>
                <dt>Name:</dt>
                <dd><input type="text" size="30" name="place"></dd>
                <dt>Address:</dt>
                <dd><input type="text" size="30" name="address"></dd>
                <dt>City:</dt>
                <dd><input type="text" size="30" name="city"></dd>
                <dt>State:</dt>
                <dd><input type="text" size="2" name="state"></dd>
                <dt>Zip Code:</dt>
                <dd><input type="text" size="10" name="zipcode"></dd>
                <dt>Nickname:</dt>
                <dd><input type="text" size="30" name="alias"></dd>
            </dl>
                <input type="submit" value="Save">
            </form>
  {% endif %}

<br>

<h3>My Places</h3>
{% include "display_posts.html" %}

{% endblock %}

I've stripped out all the validation code to try to figure this out.

layout.html (in case it helps):

<!doctype html>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<div class="page">
  <div class="metanav">
  {% if session.username %}
  Logged in as {{ session.username }}
  {% endif %}
  <a href="{{ url_for('index') }}">Home</a>
  {% if not session.username %}
    <a href="{{ url_for('register') }}">Register</a>
    <a href="{{ url_for('login') }}">Login</a>
  {% else %}
    <a href="{{ url_for('profile', username=session.username) }}">Profile</a>
    <a href="{{ url_for('logout') }}">Logout</a>
    <a href="{{ url_for('add_place') }}">Places</a>
    <a href="{{ url_for('add_trip') }}">Trips</a>
    <a href="{{ url_for('add_delegate') }}">Delegates</a>
  {% endif %}
  </div>
  {% for message in get_flashed_messages() %}
    <div class="flash">{{ message }}</div>
  {% endfor %}
  {% block body %}{% endblock %}
  {% block post %}{% endblock %}
  {% block place %}{% endblock %}
  {% block trip %}{% endblock %}
</div>

Once I open the 'index.html' version of the file and send form data, it refreshes to the correct file, but I can't go there directly without the BAD REQUEST page.

Thanks

Jeff Ericson
  • 61
  • 1
  • 9

1 Answers1

1

The issue is that you are accessing request.form without checking if request.form is populated. form contains arguments in the body of the HTTP request ... and GET requests don't have a body.

As discussed in Form sending error, Flask - when Flask is asked for a form variable that doesn't exist it throws an error ... just like an ordinary Python dictionary does.

The solution in your case is to wrap all of your data-processing code inside of a conditional:

if request.method == "POST":
    # code accessing request.form here

So the general structure is:

@app.route('/add_place', methods=['GET', 'POST'])
def add_place():
    if request.method == "POST":
        username = session['username']
        placename = request.form['place']
        # ... snip ...

    # Note that this is not under the `if`
    # so we'll *always* return this template's HTML.    
    return render_template('placeindex.html')
Community
  • 1
  • 1
Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • Thank you Sean! That makes complete sense - I was trying to figure out how Flask knew what form to load to set it up to receive the data from placeindex.html. The 'if' solves that nicely. I saw that in other examples but didn't quite get it. I tried to upvote you, but as a 'newbie' I'm not allowed to yet. – Jeff Ericson May 09 '16 at 01:58