298 lines
19 KiB
HTML
298 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="en" data-content_root="./">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Design Decisions in Flask — Flask Documentation (3.2.x)</title>
|
||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=6625fa76" />
|
||
<link rel="stylesheet" type="text/css" href="_static/flask.css?v=b87c8d14" />
|
||
<script src="_static/documentation_options.js?v=56528222"></script>
|
||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
<script data-project="flask" data-version="3.2.x" src="_static/describe_version.js?v=fa7f30d0"></script>
|
||
<link rel="icon" href="_static/shortcut-icon.png"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="next" title="Flask Extension Development" href="extensiondev.html" />
|
||
<link rel="prev" title="API" href="api.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="Related">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="extensiondev.html" title="Flask Extension Development"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="api.html" title="API"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Flask Documentation (3.2.x)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Design Decisions in Flask</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section id="design-decisions-in-flask">
|
||
<h1>Design Decisions in Flask<a class="headerlink" href="#design-decisions-in-flask" title="Link to this heading">¶</a></h1>
|
||
<p>If you are curious why Flask does certain things the way it does and not
|
||
differently, this section is for you. This should give you an idea about
|
||
some of the design decisions that may appear arbitrary and surprising at
|
||
first, especially in direct comparison with other frameworks.</p>
|
||
<section id="the-explicit-application-object">
|
||
<h2>The Explicit Application Object<a class="headerlink" href="#the-explicit-application-object" title="Link to this heading">¶</a></h2>
|
||
<p>A Python web application based on WSGI has to have one central callable
|
||
object that implements the actual application. In Flask this is an
|
||
instance of the <a class="reference internal" href="api.html#flask.Flask" title="flask.Flask"><code class="xref py py-class docutils literal notranslate"><span class="pre">Flask</span></code></a> class. Each Flask application has
|
||
to create an instance of this class itself and pass it the name of the
|
||
module, but why can’t Flask do that itself?</p>
|
||
<p>Without such an explicit application object the following code:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">Flask</span>
|
||
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
|
||
|
||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
|
||
<span class="k">return</span> <span class="s1">'Hello World!'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Would look like this instead:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">hypothetical_flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">route</span>
|
||
|
||
<span class="nd">@route</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
|
||
<span class="k">return</span> <span class="s1">'Hello World!'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>There are three major reasons for this. The most important one is that
|
||
implicit application objects require that there may only be one instance at
|
||
the time. There are ways to fake multiple applications with a single
|
||
application object, like maintaining a stack of applications, but this
|
||
causes some problems I won’t outline here in detail. Now the question is:
|
||
when does a microframework need more than one application at the same
|
||
time? A good example for this is unit testing. When you want to test
|
||
something it can be very helpful to create a minimal application to test
|
||
specific behavior. When the application object is deleted everything it
|
||
allocated will be freed again.</p>
|
||
<p>Another thing that becomes possible when you have an explicit object lying
|
||
around in your code is that you can subclass the base class
|
||
(<a class="reference internal" href="api.html#flask.Flask" title="flask.Flask"><code class="xref py py-class docutils literal notranslate"><span class="pre">Flask</span></code></a>) to alter specific behavior. This would not be
|
||
possible without hacks if the object were created ahead of time for you
|
||
based on a class that is not exposed to you.</p>
|
||
<p>But there is another very important reason why Flask depends on an
|
||
explicit instantiation of that class: the package name. Whenever you
|
||
create a Flask instance you usually pass it <code class="code docutils literal notranslate"><span class="pre">__name__</span></code> as package name.
|
||
Flask depends on that information to properly load resources relative
|
||
to your module. With Python’s outstanding support for reflection it can
|
||
then access the package to figure out where the templates and static files
|
||
are stored (see <a class="reference internal" href="api.html#flask.Flask.open_resource" title="flask.Flask.open_resource"><code class="xref py py-meth docutils literal notranslate"><span class="pre">open_resource()</span></code></a>). Now obviously there
|
||
are frameworks around that do not need any configuration and will still be
|
||
able to load templates relative to your application module. But they have
|
||
to use the current working directory for that, which is a very unreliable
|
||
way to determine where the application is. The current working directory
|
||
is process-wide and if you are running multiple applications in one
|
||
process (which could happen in a webserver without you knowing) the paths
|
||
will be off. Worse: many webservers do not set the working directory to
|
||
the directory of your application but to the document root which does not
|
||
have to be the same folder.</p>
|
||
<p>The third reason is “explicit is better than implicit”. That object is
|
||
your WSGI application, you don’t have to remember anything else. If you
|
||
want to apply a WSGI middleware, just wrap it and you’re done (though
|
||
there are better ways to do that so that you do not lose the reference
|
||
to the application object <a class="reference internal" href="api.html#flask.Flask.wsgi_app" title="flask.Flask.wsgi_app"><code class="xref py py-meth docutils literal notranslate"><span class="pre">wsgi_app()</span></code></a>).</p>
|
||
<p>Furthermore this design makes it possible to use a factory function to
|
||
create the application which is very helpful for unit testing and similar
|
||
things (<a class="reference internal" href="patterns/appfactories.html"><span class="doc">Application Factories</span></a>).</p>
|
||
</section>
|
||
<section id="the-routing-system">
|
||
<h2>The Routing System<a class="headerlink" href="#the-routing-system" title="Link to this heading">¶</a></h2>
|
||
<p>Flask uses the Werkzeug routing system which was designed to
|
||
automatically order routes by complexity. This means that you can declare
|
||
routes in arbitrary order and they will still work as expected. This is a
|
||
requirement if you want to properly implement decorator based routing
|
||
since decorators could be fired in undefined order when the application is
|
||
split into multiple modules.</p>
|
||
<p>Another design decision with the Werkzeug routing system is that routes
|
||
in Werkzeug try to ensure that URLs are unique. Werkzeug will go quite far
|
||
with that in that it will automatically redirect to a canonical URL if a route
|
||
is ambiguous.</p>
|
||
</section>
|
||
<section id="one-template-engine">
|
||
<h2>One Template Engine<a class="headerlink" href="#one-template-engine" title="Link to this heading">¶</a></h2>
|
||
<p>Flask decides on one template engine: Jinja2. Why doesn’t Flask have a
|
||
pluggable template engine interface? You can obviously use a different
|
||
template engine, but Flask will still configure Jinja2 for you. While
|
||
that limitation that Jinja2 is <em>always</em> configured will probably go away,
|
||
the decision to bundle one template engine and use that will not.</p>
|
||
<p>Template engines are like programming languages and each of those engines
|
||
has a certain understanding about how things work. On the surface they
|
||
all work the same: you tell the engine to evaluate a template with a set
|
||
of variables and take the return value as string.</p>
|
||
<p>But that’s about where similarities end. Jinja2 for example has an
|
||
extensive filter system, a certain way to do template inheritance,
|
||
support for reusable blocks (macros) that can be used from inside
|
||
templates and also from Python code, supports iterative template
|
||
rendering, configurable syntax and more. On the other hand an engine
|
||
like Genshi is based on XML stream evaluation, template inheritance by
|
||
taking the availability of XPath into account and more. Mako on the
|
||
other hand treats templates similar to Python modules.</p>
|
||
<p>When it comes to connecting a template engine with an application or
|
||
framework there is more than just rendering templates. For instance,
|
||
Flask uses Jinja2’s extensive autoescaping support. Also it provides
|
||
ways to access macros from Jinja2 templates.</p>
|
||
<p>A template abstraction layer that would not take the unique features of
|
||
the template engines away is a science on its own and a too large
|
||
undertaking for a microframework like Flask.</p>
|
||
<p>Furthermore extensions can then easily depend on one template language
|
||
being present. You can easily use your own templating language, but an
|
||
extension could still depend on Jinja itself.</p>
|
||
</section>
|
||
<section id="what-does-micro-mean">
|
||
<h2>What does “micro” mean?<a class="headerlink" href="#what-does-micro-mean" title="Link to this heading">¶</a></h2>
|
||
<p>“Micro” does not mean that your whole web application has to fit into a single
|
||
Python file (although it certainly can), nor does it mean that Flask is lacking
|
||
in functionality. The “micro” in microframework means Flask aims to keep the
|
||
core simple but extensible. Flask won’t make many decisions for you, such as
|
||
what database to use. Those decisions that it does make, such as what
|
||
templating engine to use, are easy to change. Everything else is up to you, so
|
||
that Flask can be everything you need and nothing you don’t.</p>
|
||
<p>By default, Flask does not include a database abstraction layer, form
|
||
validation or anything else where different libraries already exist that can
|
||
handle that. Instead, Flask supports extensions to add such functionality to
|
||
your application as if it was implemented in Flask itself. Numerous extensions
|
||
provide database integration, form validation, upload handling, various open
|
||
authentication technologies, and more. Flask may be “micro”, but it’s ready for
|
||
production use on a variety of needs.</p>
|
||
<p>Why does Flask call itself a microframework and yet it depends on two
|
||
libraries (namely Werkzeug and Jinja2). Why shouldn’t it? If we look
|
||
over to the Ruby side of web development there we have a protocol very
|
||
similar to WSGI. Just that it’s called Rack there, but besides that it
|
||
looks very much like a WSGI rendition for Ruby. But nearly all
|
||
applications in Ruby land do not work with Rack directly, but on top of a
|
||
library with the same name. This Rack library has two equivalents in
|
||
Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but
|
||
from my understanding it’s sort of deprecated in favour of WebOb. The
|
||
development of WebOb and Werkzeug started side by side with similar ideas
|
||
in mind: be a good implementation of WSGI for other applications to take
|
||
advantage.</p>
|
||
<p>Flask is a framework that takes advantage of the work already done by
|
||
Werkzeug to properly interface WSGI (which can be a complex task at
|
||
times). Thanks to recent developments in the Python package
|
||
infrastructure, packages with dependencies are no longer an issue and
|
||
there are very few reasons against having libraries that depend on others.</p>
|
||
</section>
|
||
<section id="thread-locals">
|
||
<h2>Thread Locals<a class="headerlink" href="#thread-locals" title="Link to this heading">¶</a></h2>
|
||
<p>Flask uses thread local objects (context local objects in fact, they
|
||
support greenlet contexts as well) for request, session and an extra
|
||
object you can put your own things on (<a class="reference internal" href="api.html#flask.g" title="flask.g"><code class="xref py py-data docutils literal notranslate"><span class="pre">g</span></code></a>). Why is that and
|
||
isn’t that a bad idea?</p>
|
||
<p>Yes it is usually not such a bright idea to use thread locals. They cause
|
||
troubles for servers that are not based on the concept of threads and make
|
||
large applications harder to maintain. However Flask is just not designed
|
||
for large applications or asynchronous servers. Flask wants to make it
|
||
quick and easy to write a traditional web application.</p>
|
||
</section>
|
||
<section id="async-await-and-asgi-support">
|
||
<h2>Async/await and ASGI support<a class="headerlink" href="#async-await-and-asgi-support" title="Link to this heading">¶</a></h2>
|
||
<p>Flask supports <code class="docutils literal notranslate"><span class="pre">async</span></code> coroutines for view functions by executing the
|
||
coroutine on a separate thread instead of using an event loop on the
|
||
main thread as an async-first (ASGI) framework would. This is necessary
|
||
for Flask to remain backwards compatible with extensions and code built
|
||
before <code class="docutils literal notranslate"><span class="pre">async</span></code> was introduced into Python. This compromise introduces
|
||
a performance cost compared with the ASGI frameworks, due to the
|
||
overhead of the threads.</p>
|
||
<p>Due to how tied to WSGI Flask’s code is, it’s not clear if it’s possible
|
||
to make the <code class="docutils literal notranslate"><span class="pre">Flask</span></code> class support ASGI and WSGI at the same time. Work
|
||
is currently being done in Werkzeug to work with ASGI, which may
|
||
eventually enable support in Flask as well.</p>
|
||
<p>See <a class="reference internal" href="async-await.html"><span class="doc">Using async and await</span></a> for more discussion.</p>
|
||
</section>
|
||
<section id="what-flask-is-what-flask-is-not">
|
||
<h2>What Flask is, What Flask is Not<a class="headerlink" href="#what-flask-is-what-flask-is-not" title="Link to this heading">¶</a></h2>
|
||
<p>Flask will never have a database layer. It will not have a form library
|
||
or anything else in that direction. Flask itself just bridges to Werkzeug
|
||
to implement a proper WSGI application and to Jinja2 to handle templating.
|
||
It also binds to a few common standard library packages such as logging.
|
||
Everything else is up for extensions.</p>
|
||
<p>Why is this the case? Because people have different preferences and
|
||
requirements and Flask could not meet those if it would force any of this
|
||
into the core. The majority of web applications will need a template
|
||
engine in some sort. However not every application needs a SQL database.</p>
|
||
<p>As your codebase grows, you are free to make the design decisions appropriate
|
||
for your project. Flask will continue to provide a very simple glue layer to
|
||
the best that Python has to offer. You can implement advanced patterns in
|
||
SQLAlchemy or another database tool, introduce non-relational data persistence
|
||
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
|
||
the Python web interface.</p>
|
||
<p>The idea of Flask is to build a good foundation for all applications.
|
||
Everything else is up to you or extensions.</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span id="sidebar-top"></span>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
||
<div class="sphinxsidebarwrapper">
|
||
|
||
|
||
<p class="logo"><a href="index.html">
|
||
<img class="logo" src="_static/flask-vertical.png" alt="Logo of Flask"/>
|
||
</a></p>
|
||
|
||
|
||
<h3>Contents</h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Design Decisions in Flask</a><ul>
|
||
<li><a class="reference internal" href="#the-explicit-application-object">The Explicit Application Object</a></li>
|
||
<li><a class="reference internal" href="#the-routing-system">The Routing System</a></li>
|
||
<li><a class="reference internal" href="#one-template-engine">One Template Engine</a></li>
|
||
<li><a class="reference internal" href="#what-does-micro-mean">What does “micro” mean?</a></li>
|
||
<li><a class="reference internal" href="#thread-locals">Thread Locals</a></li>
|
||
<li><a class="reference internal" href="#async-await-and-asgi-support">Async/await and ASGI support</a></li>
|
||
<li><a class="reference internal" href="#what-flask-is-what-flask-is-not">What Flask is, What Flask is Not</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li><a href="index.html">Overview</a>
|
||
<ul>
|
||
<li>Previous: <a href="api.html" title="previous chapter">API</a>
|
||
<li>Next: <a href="extensiondev.html" title="next chapter">Flask Extension Development</a>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<search id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</search>
|
||
<script>document.getElementById('searchbox').style.display = "block"</script><div id="ethical-ad-placement"></div>
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2010 Pallets.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||
</div>
|
||
</body>
|
||
</html>
|