Introduction Link to heading
I have been playing around with flask for few weeks now. It’s definitely leaner than Django but still there are some parts that look like black magic (I am looking at you, g).
So, Starting with…
Hello world Link to heading
This looks like a good to place to start. This is the smallest functional flask app, I guess.
Basically, there are two things happening here:
- Route registration with
@app.rount
- Web Application with
app.run()
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Hello, World!"
if __name__ == '__main__':
app.run(debug = True)
Route registration Link to heading
Let’s start with app registration part.
@app.route
defined in flask/app.py
calls add_url_rule
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
and add_url_rule
takes f as view_func
and register rule
that maps that route to view_func
def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
in the example above, endpoint
is None, endpoint is set to __name__
of the view_func
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
def _endpoint_from_view_func(view_func):
assert view_func is not None, "expected view func if endpoint is not provided."
return view_func.__name__
at this point we have rule as /
and endpoint as index
. Then, rule is used to create an object of Rule
which takes options
dict. and the newly created rule is added to url_map
To sum up, the following part registered url /
to endpoint index
options["endpoint"] = endpoint
...
...
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options
self.url_map.add(rule)
and eventually, endpoint index
is linked to the actual function view_func
using view_functions
self.view_functions[endpoint] = view_func
Web Application Link to heading
For the second part, now that I know view_functions
where the magic is, I can look for whoever doing lookup and start from there.
But we know that flask is WSGI application. So, we can start with __call__
. If you haven’t heard about WSGI before, look into pep333. The important part:
The Application/Framework Side The application object is simply a callable object that accepts two arguments. The term “object” should not be misconstrued as requiring an actual object instance: a function, method, class, or instance with a call method are all acceptable for use as an application object. Application objects must be able to be invoked more than once, as virtually all servers/gateways (other than CGI) will make such repeated requests.
So, In flask/app.py
, __call__
is defined as
def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
return self.wsgi_app(environ, start_response)
In wsgi_app
,
response = self.full_dispatch_request()
...
...
return response(environ, start_response)
in full_dispatch_request
,
def full_dispatch_request(self):
rv = self.dispatch_request()
In dispatch_request
, rule
is extract from the request and rule.endpoint
is used to lookup the registered view from, wait for it, view_functions
def dispatch_request(self):
return self.view_functions[rule.endpoint](**req.view_args)