[pre-commit.ci lite] apply automatic fixes

This commit is contained in:
pre-commit-ci-lite[bot] 2025-04-11 03:04:22 +00:00 committed by GitHub
parent b3ae3117f9
commit 3d83d8138c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
102 changed files with 26790 additions and 26749 deletions

View file

@ -5,7 +5,7 @@
<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>Lazily Loading Views &#8212; Flask Documentation (3.2.x)</title>
<title>Large Applications as Packages &#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>
@ -15,8 +15,8 @@
<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="MongoDB with MongoEngine" href="mongoengine.html" />
<link rel="prev" title="JavaScript, fetch, and JSON" href="javascript.html" />
<link rel="next" title="Application Factories" href="appfactories.html" />
<link rel="prev" title="Patterns for Flask" href="index.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
@ -28,125 +28,144 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="mongoengine.html" title="MongoDB with MongoEngine"
<a href="appfactories.html" title="Application Factories"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="javascript.html" title="JavaScript, fetch, and JSON"
<a href="index.html" title="Patterns for Flask"
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Lazily Loading Views</a></li>
<li class="nav-item nav-item-this"><a href="">Large Applications as Packages</a></li>
</ul>
</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="lazily-loading-views">
<h1>Lazily Loading Views<a class="headerlink" href="#lazily-loading-views" title="Link to this heading"></a></h1>
<p>Flask is usually used with the decorators. Decorators are simple and you
have the URL right next to the function that is called for that specific
URL. However there is a downside to this approach: it means all your code
that uses decorators has to be imported upfront or Flask will never
actually find your function.</p>
<p>This can be a problem if your application has to import quick. It might
have to do that on systems like Googles App Engine or other systems. So
if you suddenly notice that your application outgrows this approach you
can fall back to a centralized URL mapping.</p>
<p>The system that enables having a central URL map is the
<a class="reference internal" href="../api.html#flask.Flask.add_url_rule" title="flask.Flask.add_url_rule"><code class="xref py py-meth docutils literal notranslate"><span class="pre">add_url_rule()</span></code></a> function. Instead of using decorators,
you have a file that sets up the application with all URLs.</p>
<section id="converting-to-centralized-url-map">
<h2>Converting to Centralized URL Map<a class="headerlink" href="#converting-to-centralized-url-map" title="Link to this heading"></a></h2>
<p>Imagine the current application looks somewhat like this:</p>
<section id="large-applications-as-packages">
<h1>Large Applications as Packages<a class="headerlink" href="#large-applications-as-packages" title="Link to this heading"></a></h1>
<p>Imagine a simple flask application structure that looks like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/</span><span class="n">yourapplication</span>
<span class="n">yourapplication</span><span class="o">.</span><span class="n">py</span>
<span class="o">/</span><span class="n">static</span>
<span class="n">style</span><span class="o">.</span><span class="n">css</span>
<span class="o">/</span><span class="n">templates</span>
<span class="n">layout</span><span class="o">.</span><span class="n">html</span>
<span class="n">index</span><span class="o">.</span><span class="n">html</span>
<span class="n">login</span><span class="o">.</span><span class="n">html</span>
<span class="o">...</span>
</pre></div>
</div>
<p>While this is fine for small applications, for larger applications
its a good idea to use a package instead of a module.
The <a class="reference internal" href="../tutorial/index.html"><span class="doc">Tutorial</span></a> is structured to use the package pattern,
see the <a class="reference external" href="https://github.com/pallets/flask/tree/main/examples/tutorial">example code</a>.</p>
<section id="simple-packages">
<h2>Simple Packages<a class="headerlink" href="#simple-packages" title="Link to this heading"></a></h2>
<p>To convert that into a larger one, just create a new folder
<code class="file docutils literal notranslate"><span class="pre">yourapplication</span></code> inside the existing one and move everything below it.
Then rename <code class="file docutils literal notranslate"><span class="pre">yourapplication.py</span></code> to <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code>. (Make sure to delete
all <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> files first, otherwise things would most likely break)</p>
<p>You should then end up with something like that:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/</span><span class="n">yourapplication</span>
<span class="o">/</span><span class="n">yourapplication</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="o">/</span><span class="n">static</span>
<span class="n">style</span><span class="o">.</span><span class="n">css</span>
<span class="o">/</span><span class="n">templates</span>
<span class="n">layout</span><span class="o">.</span><span class="n">html</span>
<span class="n">index</span><span class="o">.</span><span class="n">html</span>
<span class="n">login</span><span class="o">.</span><span class="n">html</span>
<span class="o">...</span>
</pre></div>
</div>
<p>But how do you run your application now? The naive <code class="docutils literal notranslate"><span class="pre">python</span>
<span class="pre">yourapplication/__init__.py</span></code> will not work. Lets just say that Python
does not want modules in packages to be the startup file. But that is not
a big problem, just add a new file called <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> next to the inner
<code class="file docutils literal notranslate"><span class="pre">yourapplication</span></code> folder with the following contents:</p>
<div class="highlight-toml notranslate"><div class="highlight"><pre><span></span><span class="k">[project]</span>
<span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;yourapplication&quot;</span>
<span class="n">dependencies</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">&quot;flask&quot;</span><span class="p">,</span>
<span class="p">]</span>
<span class="k">[build-system]</span>
<span class="n">requires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;flit_core&lt;4&quot;</span><span class="p">]</span>
<span class="n">build-backend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;flit_core.buildapi&quot;</span>
</pre></div>
</div>
<p>Install your application so it is importable:</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ pip install -e .
</pre></div>
</div>
<p>To use the <code class="docutils literal notranslate"><span class="pre">flask</span></code> command and run your application you need to set
the <code class="docutils literal notranslate"><span class="pre">--app</span></code> option that tells Flask where to find the application
instance:</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ flask --app yourapplication run
</pre></div>
</div>
<p>What did we gain from this? Now we can restructure the application a bit
into multiple modules. The only thing you have to remember is the
following quick checklist:</p>
<ol class="arabic simple">
<li><p>the <code class="code docutils literal notranslate"><span class="pre">Flask</span></code> application object creation has to be in the
<code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code> file. That way each module can import it safely and the
<code class="code docutils literal notranslate"><span class="pre">__name__</span></code> variable will resolve to the correct package.</p></li>
<li><p>all the view functions (the ones with a <a class="reference internal" href="../api.html#flask.Flask.route" title="flask.Flask.route"><code class="xref py py-meth docutils literal notranslate"><span class="pre">route()</span></code></a>
decorator on top) have to be imported in the <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code> file.
Not the object itself, but the module it is in. Import the view module
<strong>after the application object is created</strong>.</p></li>
</ol>
<p>Heres an example <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></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="kn">import</span><span class="w"> </span><span class="nn">yourapplication.views</span>
</pre></div>
</div>
<p>And this is what <code class="file docutils literal notranslate"><span class="pre">views.py</span></code> would look like:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication</span><span class="w"> </span><span class="kn">import</span> <span class="n">app</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">pass</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/user/&lt;username&gt;&#39;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">user</span><span class="p">(</span><span class="n">username</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">return</span> <span class="s1">&#39;Hello World!&#39;</span>
</pre></div>
</div>
<p>Then, with the centralized approach you would have one file with the views
(<code class="file docutils literal notranslate"><span class="pre">views.py</span></code>) but without any decorator:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
<span class="k">pass</span>
<span class="k">def</span><span class="w"> </span><span class="nf">user</span><span class="p">(</span><span class="n">username</span><span class="p">):</span>
<span class="k">pass</span>
<p>You should then end up with something like that:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">/</span><span class="n">yourapplication</span>
<span class="n">pyproject</span><span class="o">.</span><span class="n">toml</span>
<span class="o">/</span><span class="n">yourapplication</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">views</span><span class="o">.</span><span class="n">py</span>
<span class="o">/</span><span class="n">static</span>
<span class="n">style</span><span class="o">.</span><span class="n">css</span>
<span class="o">/</span><span class="n">templates</span>
<span class="n">layout</span><span class="o">.</span><span class="n">html</span>
<span class="n">index</span><span class="o">.</span><span class="n">html</span>
<span class="n">login</span><span class="o">.</span><span class="n">html</span>
<span class="o">...</span>
</pre></div>
</div>
<p>And then a file that sets up an application which maps the functions to
URLs:</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="kn">from</span><span class="w"> </span><span class="nn">yourapplication</span><span class="w"> </span><span class="kn">import</span> <span class="n">views</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="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="n">view_func</span><span class="o">=</span><span class="n">views</span><span class="o">.</span><span class="n">index</span><span class="p">)</span>
<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s1">&#39;/user/&lt;username&gt;&#39;</span><span class="p">,</span> <span class="n">view_func</span><span class="o">=</span><span class="n">views</span><span class="o">.</span><span class="n">user</span><span class="p">)</span>
</pre></div>
<div class="admonition-circular-imports admonition">
<p class="admonition-title">Circular Imports</p>
<p>Every Python programmer hates them, and yet we just added some:
circular imports (Thats when two modules depend on each other. In this
case <code class="file docutils literal notranslate"><span class="pre">views.py</span></code> depends on <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code>). Be advised that this is a
bad idea in general but here it is actually fine. The reason for this is
that we are not actually using the views in <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code> and just
ensuring the module is imported and we are doing that at the bottom of
the file.</p>
</div>
</section>
<section id="loading-late">
<h2>Loading Late<a class="headerlink" href="#loading-late" title="Link to this heading"></a></h2>
<p>So far we only split up the views and the routing, but the module is still
loaded upfront. The trick is to actually load the view function as needed.
This can be accomplished with a helper class that behaves just like a
function but internally imports the real function on first use:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">import_string</span><span class="p">,</span> <span class="n">cached_property</span>
<span class="k">class</span><span class="w"> </span><span class="nc">LazyView</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">import_name</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="vm">__module__</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">=</span> <span class="n">import_name</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">import_name</span> <span class="o">=</span> <span class="n">import_name</span>
<span class="nd">@cached_property</span>
<span class="k">def</span><span class="w"> </span><span class="nf">view</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="n">import_string</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">import_name</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>Whats important here is is that <code class="code docutils literal notranslate"><span class="pre">__module__</span></code> and <code class="code docutils literal notranslate"><span class="pre">__name__</span></code> are properly
set. This is used by Flask internally to figure out how to name the
URL rules in case you dont provide a name for the rule yourself.</p>
<p>Then you can define your central place to combine the views like this:</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="kn">from</span><span class="w"> </span><span class="nn">yourapplication.helpers</span><span class="w"> </span><span class="kn">import</span> <span class="n">LazyView</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="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span>
<span class="n">view_func</span><span class="o">=</span><span class="n">LazyView</span><span class="p">(</span><span class="s1">&#39;yourapplication.views.index&#39;</span><span class="p">))</span>
<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s1">&#39;/user/&lt;username&gt;&#39;</span><span class="p">,</span>
<span class="n">view_func</span><span class="o">=</span><span class="n">LazyView</span><span class="p">(</span><span class="s1">&#39;yourapplication.views.user&#39;</span><span class="p">))</span>
</pre></div>
</div>
<p>You can further optimize this in terms of amount of keystrokes needed to
write this by having a function that calls into
<a class="reference internal" href="../api.html#flask.Flask.add_url_rule" title="flask.Flask.add_url_rule"><code class="xref py py-meth docutils literal notranslate"><span class="pre">add_url_rule()</span></code></a> by prefixing a string with the project
name and a dot, and by wrapping <code class="code docutils literal notranslate"><span class="pre">view_func</span></code> in a <code class="code docutils literal notranslate"><span class="pre">LazyView</span></code> as needed.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">url</span><span class="p">(</span><span class="n">import_name</span><span class="p">,</span> <span class="n">url_rules</span><span class="o">=</span><span class="p">[],</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
<span class="n">view</span> <span class="o">=</span> <span class="n">LazyView</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;yourapplication.</span><span class="si">{</span><span class="n">import_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">url_rule</span> <span class="ow">in</span> <span class="n">url_rules</span><span class="p">:</span>
<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="n">url_rule</span><span class="p">,</span> <span class="n">view_func</span><span class="o">=</span><span class="n">view</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span>
<span class="c1"># add a single route to the index view</span>
<span class="n">url</span><span class="p">(</span><span class="s1">&#39;views.index&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;/&#39;</span><span class="p">])</span>
<span class="c1"># add two routes to a single function endpoint</span>
<span class="n">url_rules</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/user/&#39;</span><span class="p">,</span><span class="s1">&#39;/user/&lt;username&gt;&#39;</span><span class="p">]</span>
<span class="n">url</span><span class="p">(</span><span class="s1">&#39;views.user&#39;</span><span class="p">,</span> <span class="n">url_rules</span><span class="p">)</span>
</pre></div>
</div>
<p>One thing to keep in mind is that before and after request handlers have
to be in a file that is imported upfront to work properly on the first
request. The same goes for any kind of remaining decorator.</p>
<section id="working-with-blueprints">
<h2>Working with Blueprints<a class="headerlink" href="#working-with-blueprints" title="Link to this heading"></a></h2>
<p>If you have larger applications its recommended to divide them into
smaller groups where each group is implemented with the help of a
blueprint. For a gentle introduction into this topic refer to the
<a class="reference internal" href="../blueprints.html"><span class="doc">Modular Applications with Blueprints</span></a> chapter of the documentation.</p>
</section>
</section>
@ -158,18 +177,18 @@ request. The same goes for any kind of remaining decorator.</p>
<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="#">Lazily Loading Views</a><ul>
<li><a class="reference internal" href="#converting-to-centralized-url-map">Converting to Centralized URL Map</a></li>
<li><a class="reference internal" href="#loading-late">Loading Late</a></li>
<li><a class="reference internal" href="#">Large Applications as Packages</a><ul>
<li><a class="reference internal" href="#simple-packages">Simple Packages</a></li>
<li><a class="reference internal" href="#working-with-blueprints">Working with Blueprints</a></li>
</ul>
</li>
</ul>
@ -179,8 +198,8 @@ request. The same goes for any kind of remaining decorator.</p>
<ul>
<li><a href="index.html">Patterns for Flask</a>
<ul>
<li>Previous: <a href="javascript.html" title="previous chapter">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a>
<li>Next: <a href="mongoengine.html" title="next chapter">MongoDB with MongoEngine</a></ul>
<li>Previous: <a href="index.html" title="previous chapter">Patterns for Flask</a>
<li>Next: <a href="appfactories.html" title="next chapter">Application Factories</a></ul>
</li>
</ul>
</li>
@ -204,4 +223,4 @@ request. The same goes for any kind of remaining decorator.</p>
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
</div>
</body>
</html>
</html>