flask/flask-docs/design.html
2025-04-10 22:13:49 +00:00

298 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 &#8212; 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> &#187;</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 cant 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">&#39;/&#39;</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">&#39;Hello World!&#39;</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">&#39;/&#39;</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">&#39;Hello World!&#39;</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 wont 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 Pythons 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 dont have to remember anything else. If you
want to apply a WSGI middleware, just wrap it and youre 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 doesnt 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 thats 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 Jinja2s 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 wont 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 dont.</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 its 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 shouldnt it? If we look
over to the Ruby side of web development there we have a protocol very
similar to WSGI. Just that its 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 its 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
isnt 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 Flasks code is, its not clear if its 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">
&#169; Copyright 2010 Pallets.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
</div>
</body>
</html>