Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad Request Error with flask, python, HTML, unusual initialization behavior with flask.request.form

I'm writing a web-app using flask, python and HTML. My issue is that the first time I load the a webpage, I get the following error

Bad Request The browser (or proxy) sent a request that this server could not understand.

I'm able to get the page to load eventually by "tricking" first running it without any flask.request.form calls, and then putting them back in (details below). Something must be going wrong in my initialization. I'm new to flask and using python with HTML.

Assume I'm working from a directory called example. I have a python script called test.py and an HTML template called test.html with the following directory structure:

\example\test.py
\example\templates\test.html

My python script test.py is:

import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"

class View(flask.views.MethodView):
    def get(self):
        result = flask.request.form['result']
        return flask.render_template('test.html', result=result)
#       return flask.render_template('test.html')
    def post(self):
        return self.get()

app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()

and my HTML in test.html is

<html>
    <head>
    </head>
    <body>
        <form action="/" method="post">
            Enter something into the box:
            <input type="text" name="result"/><br>
            <input type="submit" value="Execute!"/>
        </form>
    </body>
</html>

Steps to reproduce the error

1: Run the test.py script, and open up the URL in a browser

Running on http://127.0.0.1:5000/

You should see the following error

Bad Request The browser (or proxy) sent a request that this server could not understand.

2: Comment out the first 2 lines of the def get(self) function and uncomment the 3rd line of the def get(self) function so that test.py looks like this

import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"

class View(flask.views.MethodView):
    def get(self):
#       result = flask.request.form['result']
#       return flask.render_template('test.html', result=result)
        return flask.render_template('test.html')
    def post(self):
        return self.get()

app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()

3: Refresh the URL, and you will see that things work (though I ultimately want to be able to return the value of result

4: Now, switch the lines that are commented out again. I.e, uncomment the first 2 lines of the def get(self) function and comment out the 3rd line of the def get(self) function so that test.py looks like this

import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"

class View(flask.views.MethodView):
    def get(self):
        result = flask.request.form['result']
        return flask.render_template('test.html', result=result)
#       return flask.render_template('test.html')
    def post(self):
        return self.get()

app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()

5: Refresh the URL and now you see things will be working as desired.

This is just a toy example illustrating the real problem exhibiting this weird behavior of how I have to "trick" my browser into showing me this webpage. The

like image 502
erin Avatar asked Aug 19 '12 02:08

erin


1 Answers

The issue here is that you are attempting to access POSTed variables in a method that will only handle GET requests. When you attempt to access a query string or POST parameter that is not set Flask will, by default, raise a BadRequest error (because you are asking for something that the person hitting the page did not supply).

What happens if the key does not exist in the form attribute? In that case a special KeyError is raised. You can catch it like a standard KeyError but if you don’t do that, a HTTP 400 Bad Request error page is shown instead. So for many situations you don’t have to deal with that problem.

If you need to access a variable from either request.args (GET) or request.form (POST) and you don't need it to be set use the get method to get the value if it is there (or None if it is not set.

# Will default to None
your_var = request.form.get("some_key")

# Alternately:
your_var = request.form.get("some_key", "alternate_default_value")

Here's an alternate way of structuring your code:

import sys
import flask, flask.views

app = flask.Flask(__name__)

app.secret_key = "bacon"
app.debug = True


class View(flask.views.MethodView):
    def get(self):
        """Enable user to provide us with input"""
        return self._default_actions()

    def post(self):
        """Map user input to our program's inputs - display errors if required"""
        result = flask.request.form['result']
        # Alternately, if `result` is not *required*
        # result = flask.request.form.get("result")
        return self._default_actions(result=result)

    def _default_actions(self, result=None):
        """Deal with the meat of the matter, taking in whatever params we need
        to get or process our information"""
        if result is None:
            return flask.render_template("test.html")
        else:
            return flask.render_template("test.html", result=result)

app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])

if __name__ == "__main__":
    app.run()
like image 159
Sean Vieira Avatar answered Sep 30 '22 08:09

Sean Vieira