URL Mapping in Flask

Posted on with tags: flask / python

URL Mapping (or URL Routing) is not a big topic in Flask. The Flask documentation has a very short section on URL Route Registrations. Miguel Grinberg’s Flask Web Development (2nd) book only discusses the topic briefly on pages 8-9 and 36-38. The route decorator is very straightforward to use in Flask.

@app.route('/)
def index():
    ....

@app.route('/user/<name>')
def user(name):
    ....

You can define the route function first and call add_url_rule method of Flask class to add the url rule.

def index():
    ....

app.add_url_rule('/', 'index', index)

If the URL mapping is only one directional that maps a URL route to a function, the Python code implementing it should be simple. The URL mapping can also do reverse mapping. When you have an end point name index, you can call url_for('index') to get the URL route /, or call url_for('user', name='john') to get the route /user/john.

Let’s look at the Flask source code to know more about URL mapping. The __init__ method of Flask class defines an instance variable url_map on Line 582.

self.url_map = self.url_map_class()
self.url_map.host_matching = host_matching

The url_map_class is a class variable defined on Line 366 which is Map class imported from werkzeug.routing module.

The add_url_rule method is defined on Line 1177 in app.py module. The method is quite long, and part of the code is shown below.

if endpoint is None:
    endpoint = _endpoint_from_view_func(view_func)
...
rule = self.url_rule_class(rule, methods=methods, **options)
...
self.url_map.add(rule)
...

if view_func is not None:
    ...
    self.view_functions[endpoint] = view_func

The url_rule_class is referring to Rule class imported from werkzeug.routing.
The view_functions is one of the instance variables (dictionary) of Flask class defined on Line 444.

The route decorator is defined on Line 1288. It calls the add_url_method method, and the code is shown below.

def route(self, rule, **options):
        def decorator(f):
            endpoint = options.pop("endpoint", None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f

        return decorator

The route decorator is interesting. If you read Miguel Grinberg’s ultimate guide to Python decorators, it is a combination of Function Registration and Decorators with Arguments.

The URL reverse function url_for is defined on Line 226 of helpers.py module. The functions retrieves a url_adapter from request context or app context, and calls build method on url_adapter to return the reversed URL.

appctx = _app_ctx_stack.top
reqctx = _request_ctx_stack.top

if reqctx is not None:
    url_adapter = reqctx.url_adapter
    ...
else:
    url_adapter = appctx.url_adapter
...
rv = url_adapter.build(
    endpoint, values, method=method, force_external=external
)

When does this url_adapter is initialized? The url_adapter is one of instance variables of RequestContext class defined on Line 290 in ctx.py module.

def __init__(self, app, environ, request=None, session=None):
    ....
    self.url_adapter = None
    try:
        self.url_adapter = app.create_url_adapter(self.request)
    ...

The url_adapter is also one of the instance variables of AppContext class defined on Line 216 in ctx.py module.

def __init__(self, app):
    ...
    self.url_adapter = app.create_url_adapter(None)

The create_url_adapter method of Flask class calls bind_to_environ or bind method of Map class to create an instance of MapAdapter class, which is also defined in werkzeug routing module.

The actual URL mapping happens on Line 2447 of app.py module (inside wsgi_app method) in Flask. It calls full_dispatch_request method of Flask class, which is defined on Line 1938. It then calls dispatch_request method, which is in turn defined on Line 1914.

def dispatch_request(self):
    """Does the request dispatching.  Matches the URL and returns the
    return value of the view or error handler. ...
    """
    ...
    return self.view_functions[rule.endpoint](**req.view_args)

The method simply uses the view_functions instance variable (a dictionary) to find the corresponding view function for the URL.

The URL Routing functions are mainly provided by the Werkzeug package, which is one of the dependent packages of Flask. The Werkzeug documentation has a page specifically for URL Routing.