Flask

Routing

Basic Routes

Routes in Flask can be defined using the route decorator of the Flask application instance:

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello Flask'

The route decorator takes a string which is the URL to match. When a request for a URL that matches this string is received by the application, the function decorated (also called a view function) will be invoked. So for an about route we would have:

@app.route('/about')
def about():
    return 'About page'

It’s important to note that these routes are not regular expressions like they are in Django.

You can also define variable rules to extract URL segment values into variables:

@app.route('/blog/posts/<post_id>')
def get_blog_post(post_id):
    # look up the blog post with id post_id
    # return some kind of HTML

Here the variable rule is in the last segment of the URL. Whatever value is in the last segment of the URL will be passed to the view function (get_blog_post) as the post_id parameter. So a request to /blog/posts/42 will retrieve (or attempt to retrieve) the blog post with an id of 42.

It is also common to reuse URLs. For example maybe we want to have /blog/posts return a list of all blog posts. So we could have two routes for the same view function:

@app.route('/blog/posts')
@app.route('/blog/posts/<post_id>')
def get_blog_post(post_id=None):
    # get the post or list of posts

Note here that we also have to supply the default value of None for the post_id in get_blog_post. When the first route is matched, there will be no value to pass to the view function.

Also note that by default the type of a variable rule is a string. However, you can specify several different types such as int and float by prefixing the variable:

@app.route('/blog/post/<int:post_id>')

Flask’s built-in URL-converters are:

string | Accepts any text without a slash (the default).
int    | Accepts integers.
float  | Like int but for floating point values.
path   | Like string but accepts slashes.
any    | Matches one of the items provided
uuid   | Accepts UUID strings

Should we try to visit the URL /blog/post/foo with a value in the last URL segment that cannot be converted to an integer, the application would return a 404 error. This is the correct action because there is not a rule with /blog/post and a string in the last segment.

Finally, routes can be configured to accept HTTP methods as well. The route decorator takes a methods keyword argument which is a list of string representing the acceptable HTTP methods for this route. As you might have assumed, the default is GET only. If we had a form to add a new blog post and wanted to return the HTML for the GET request and parse the form data for the POST request, the route would look something like this:

@app.route('/blog/new', methods=['GET', 'POST'])
def new_post():
    if request.method == 'GET':
        # return the form
    elif request.method == 'POST':
        # get the data from the form values

The request is found in the flask package. Note that when using the methods keyword argument, we must be explicit about the HTTP methods to accept. If we had listed only POST, the route would no longer respond to GET requests and return a 405 error.

Catch-all route

It may be useful to have one catch-all view where you handle complex logic yourself based on the path. This example uses two rules: The first rule specifically catches / and the second rule catches arbitrary paths with the built-in path converter. The path converter matches any string (including slashes) See Flask Variable-Rules

@app.route('/', defaults={'u_path': ''})
@app.route('/<path:u_path>')
def catch_all(u_path):
    print(repr(u_path))
    ...
c = app.test_client()
c.get('/')  # u_path = ''
c.get('/hello')  # u_path = 'hello'
c.get('/hello/stack/overflow/')  # u_path = 'hello/stack/overflow/'

Routing and HTTP methods

By default, routes only respond to GET requests. You can change this behavior by supplying the methods argument to the route() decorator.

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        do_the_login()
    else:
        show_the_login_form()

You can also map different functions to the same endpoint based on the HTTP method used.

@app.route('/endpoint', methods=['GET'])
def get_endpoint():
    #respond to GET requests for '/endpoint'


@app.route('/endpoint', methods=['POST', 'PUT', 'DELETE'])
def post_or_put():
    #respond to POST, PUT, or DELETE requests for '/endpoint'

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow