[pre-commit.ci lite] apply automatic fixes
This commit is contained in:
parent
b3ae3117f9
commit
3d83d8138c
102 changed files with 26790 additions and 26749 deletions
|
|
@ -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>Application Dispatching — Flask Documentation (3.2.x)</title>
|
||||
<title>Background Tasks with Celery — 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="Using URL Processors" href="urlprocessors.html" />
|
||||
<link rel="prev" title="Application Factories" href="appfactories.html" />
|
||||
<link rel="next" title="Subclassing Flask" href="subclassing.html" />
|
||||
<link rel="prev" title="Request Content Checksums" href="requestchecksum.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,186 +28,212 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="urlprocessors.html" title="Using URL Processors"
|
||||
<a href="subclassing.html" title="Subclassing Flask"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="appfactories.html" title="Application Factories"
|
||||
<a href="requestchecksum.html" title="Request Content Checksums"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Application Dispatching</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Background Tasks with Celery</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="application-dispatching">
|
||||
<h1>Application Dispatching<a class="headerlink" href="#application-dispatching" title="Link to this heading">¶</a></h1>
|
||||
<p>Application dispatching is the process of combining multiple Flask
|
||||
applications on the WSGI level. You can combine not only Flask
|
||||
applications but any WSGI application. This would allow you to run a
|
||||
Django and a Flask application in the same interpreter side by side if
|
||||
you want. The usefulness of this depends on how the applications work
|
||||
internally.</p>
|
||||
<p>The fundamental difference from <a class="reference internal" href="packages.html"><span class="doc">Large Applications as Packages</span></a> is that in this case you
|
||||
are running the same or different Flask applications that are entirely
|
||||
isolated from each other. They run different configurations and are
|
||||
dispatched on the WSGI level.</p>
|
||||
<section id="working-with-this-document">
|
||||
<h2>Working with this Document<a class="headerlink" href="#working-with-this-document" title="Link to this heading">¶</a></h2>
|
||||
<p>Each of the techniques and examples below results in an <code class="docutils literal notranslate"><span class="pre">application</span></code>
|
||||
object that can be run with any WSGI server. For development, use the
|
||||
<code class="docutils literal notranslate"><span class="pre">flask</span> <span class="pre">run</span></code> command to start a development server. For production, see
|
||||
<a class="reference internal" href="../deploying/index.html"><span class="doc">Deploying to Production</span></a>.</p>
|
||||
|
||||
<section id="background-tasks-with-celery">
|
||||
<h1>Background Tasks with Celery<a class="headerlink" href="#background-tasks-with-celery" title="Link to this heading">¶</a></h1>
|
||||
<p>If your application has a long running task, such as processing some uploaded data or
|
||||
sending email, you don’t want to wait for it to finish during a request. Instead, use a
|
||||
task queue to send the necessary data to another process that will run the task in the
|
||||
background while the request returns immediately.</p>
|
||||
<p><a class="reference external" href="https://celery.readthedocs.io">Celery</a> is a powerful task queue that can be used for simple background tasks as well
|
||||
as complex multi-stage programs and schedules. This guide will show you how to configure
|
||||
Celery using Flask. Read Celery’s <a class="reference external" href="https://celery.readthedocs.io/en/latest/getting-started/first-steps-with-celery.html">First Steps with Celery</a> guide to learn how to use
|
||||
Celery itself.</p>
|
||||
<p>The Flask repository contains <a class="reference external" href="https://github.com/pallets/flask/tree/main/examples/celery">an example</a>
|
||||
based on the information on this page, which also shows how to use JavaScript to submit
|
||||
tasks and poll for progress and results.</p>
|
||||
<section id="install">
|
||||
<h2>Install<a class="headerlink" href="#install" title="Link to this heading">¶</a></h2>
|
||||
<p>Install Celery from PyPI, for example using pip:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ pip install celery
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="integrate-celery-with-flask">
|
||||
<h2>Integrate Celery with Flask<a class="headerlink" href="#integrate-celery-with-flask" title="Link to this heading">¶</a></h2>
|
||||
<p>You can use Celery without any integration with Flask, but it’s convenient to configure
|
||||
it through Flask’s config, and to let tasks access the Flask application.</p>
|
||||
<p>Celery uses similar ideas to Flask, with a <code class="docutils literal notranslate"><span class="pre">Celery</span></code> app object that has configuration
|
||||
and registers tasks. While creating a Flask app, use the following code to create and
|
||||
configure a Celery app as well.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">celery</span><span class="w"> </span><span class="kn">import</span> <span class="n">Celery</span><span class="p">,</span> <span class="n">Task</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">celery_init_app</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">Flask</span><span class="p">)</span> <span class="o">-></span> <span class="n">Celery</span><span class="p">:</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">FlaskTask</span><span class="p">(</span><span class="n">Task</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="nb">object</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="nb">object</span><span class="p">:</span>
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">app_context</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">run</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="n">celery_app</span> <span class="o">=</span> <span class="n">Celery</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">task_cls</span><span class="o">=</span><span class="n">FlaskTask</span><span class="p">)</span>
|
||||
<span class="n">celery_app</span><span class="o">.</span><span class="n">config_from_object</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s2">"CELERY"</span><span class="p">])</span>
|
||||
<span class="n">celery_app</span><span class="o">.</span><span class="n">set_default</span><span class="p">()</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">extensions</span><span class="p">[</span><span class="s2">"celery"</span><span class="p">]</span> <span class="o">=</span> <span class="n">celery_app</span>
|
||||
<span class="k">return</span> <span class="n">celery_app</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This creates and returns a <code class="docutils literal notranslate"><span class="pre">Celery</span></code> app object. Celery <a class="reference external" href="https://celery.readthedocs.io/en/stable/userguide/configuration.html">configuration</a> is taken from
|
||||
the <code class="docutils literal notranslate"><span class="pre">CELERY</span></code> key in the Flask configuration. The Celery app is set as the default, so
|
||||
that it is seen during each request. The <code class="docutils literal notranslate"><span class="pre">Task</span></code> subclass automatically runs task
|
||||
functions with a Flask app context active, so that services like your database
|
||||
connections are available.</p>
|
||||
<p>Here’s a basic <code class="docutils literal notranslate"><span class="pre">example.py</span></code> that configures Celery to use Redis for communication. We
|
||||
enable a result backend, but ignore results by default. This allows us to store results
|
||||
only for tasks where we care about the result.</p>
|
||||
<div class="highlight-python 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">hello_world</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="s1">'Hello World!'</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_mapping</span><span class="p">(</span>
|
||||
<span class="n">CELERY</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span>
|
||||
<span class="n">broker_url</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">result_backend</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">task_ignore_result</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">celery_app</span> <span class="o">=</span> <span class="n">celery_init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Point the <code class="docutils literal notranslate"><span class="pre">celery</span> <span class="pre">worker</span></code> command at this and it will find the <code class="docutils literal notranslate"><span class="pre">celery_app</span></code> object.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ celery -A example worker --loglevel INFO
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also run the <code class="docutils literal notranslate"><span class="pre">celery</span> <span class="pre">beat</span></code> command to run tasks on a schedule. See Celery’s
|
||||
docs for more information about defining schedules.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ celery -A example beat --loglevel INFO
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="combining-applications">
|
||||
<h2>Combining Applications<a class="headerlink" href="#combining-applications" title="Link to this heading">¶</a></h2>
|
||||
<p>If you have entirely separated applications and you want them to work next
|
||||
to each other in the same Python interpreter process you can take
|
||||
advantage of the <code class="xref py py-class docutils literal notranslate"><span class="pre">werkzeug.wsgi.DispatcherMiddleware</span></code>. The idea
|
||||
here is that each Flask application is a valid WSGI application and they
|
||||
are combined by the dispatcher middleware into a larger one that is
|
||||
dispatched based on prefix.</p>
|
||||
<p>For example you could have your main application run on <code class="docutils literal notranslate"><span class="pre">/</span></code> and your
|
||||
backend interface on <code class="docutils literal notranslate"><span class="pre">/backend</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.middleware.dispatcher</span><span class="w"> </span><span class="kn">import</span> <span class="n">DispatcherMiddleware</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">frontend_app</span><span class="w"> </span><span class="kn">import</span> <span class="n">application</span> <span class="k">as</span> <span class="n">frontend</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">backend_app</span><span class="w"> </span><span class="kn">import</span> <span class="n">application</span> <span class="k">as</span> <span class="n">backend</span>
|
||||
<section id="application-factory">
|
||||
<h2>Application Factory<a class="headerlink" href="#application-factory" title="Link to this heading">¶</a></h2>
|
||||
<p>When using the Flask application factory pattern, call the <code class="docutils literal notranslate"><span class="pre">celery_init_app</span></code> function
|
||||
inside the factory. It sets <code class="docutils literal notranslate"><span class="pre">app.extensions["celery"]</span></code> to the Celery app object, which
|
||||
can be used to get the Celery app from the Flask app returned by the factory.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">create_app</span><span class="p">()</span> <span class="o">-></span> <span class="n">Flask</span><span class="p">:</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">config</span><span class="o">.</span><span class="n">from_mapping</span><span class="p">(</span>
|
||||
<span class="n">CELERY</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span>
|
||||
<span class="n">broker_url</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">result_backend</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">task_ignore_result</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_prefixed_env</span><span class="p">()</span>
|
||||
<span class="n">celery_init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">app</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To use <code class="docutils literal notranslate"><span class="pre">celery</span></code> commands, Celery needs an app object, but that’s no longer directly
|
||||
available. Create a <code class="docutils literal notranslate"><span class="pre">make_celery.py</span></code> file that calls the Flask app factory and gets
|
||||
the Celery app from the returned Flask app.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">example</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_app</span>
|
||||
|
||||
<span class="n">application</span> <span class="o">=</span> <span class="n">DispatcherMiddleware</span><span class="p">(</span><span class="n">frontend</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="s1">'/backend'</span><span class="p">:</span> <span class="n">backend</span>
|
||||
<span class="p">})</span>
|
||||
<span class="n">flask_app</span> <span class="o">=</span> <span class="n">create_app</span><span class="p">()</span>
|
||||
<span class="n">celery_app</span> <span class="o">=</span> <span class="n">flask_app</span><span class="o">.</span><span class="n">extensions</span><span class="p">[</span><span class="s2">"celery"</span><span class="p">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Point the <code class="docutils literal notranslate"><span class="pre">celery</span></code> command to this file.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ celery -A make_celery worker --loglevel INFO
|
||||
$ celery -A make_celery beat --loglevel INFO
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="dispatch-by-subdomain">
|
||||
<h2>Dispatch by Subdomain<a class="headerlink" href="#dispatch-by-subdomain" title="Link to this heading">¶</a></h2>
|
||||
<p>Sometimes you might want to use multiple instances of the same application
|
||||
with different configurations. Assuming the application is created inside
|
||||
a function and you can call that function to instantiate it, that is
|
||||
really easy to implement. In order to develop your application to support
|
||||
creating new instances in functions have a look at the
|
||||
<a class="reference internal" href="appfactories.html"><span class="doc">Application Factories</span></a> pattern.</p>
|
||||
<p>A very common example would be creating applications per subdomain. For
|
||||
instance you configure your webserver to dispatch all requests for all
|
||||
subdomains to your application and you then use the subdomain information
|
||||
to create user-specific instances. Once you have your server set up to
|
||||
listen on all subdomains you can use a very simple WSGI application to do
|
||||
the dynamic application creation.</p>
|
||||
<p>The perfect level for abstraction in that regard is the WSGI layer. You
|
||||
write your own WSGI application that looks at the request that comes and
|
||||
delegates it to your Flask application. If that application does not
|
||||
exist yet, it is dynamically created and remembered.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">threading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Lock</span>
|
||||
<section id="defining-tasks">
|
||||
<h2>Defining Tasks<a class="headerlink" href="#defining-tasks" title="Link to this heading">¶</a></h2>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">@celery_app.task</span></code> to decorate task functions requires access to the
|
||||
<code class="docutils literal notranslate"><span class="pre">celery_app</span></code> object, which won’t be available when using the factory pattern. It also
|
||||
means that the decorated tasks are tied to the specific Flask and Celery app instances,
|
||||
which could be an issue during testing if you change configuration for a test.</p>
|
||||
<p>Instead, use Celery’s <code class="docutils literal notranslate"><span class="pre">@shared_task</span></code> decorator. This creates task objects that will
|
||||
access whatever the “current app” is, which is a similar concept to Flask’s blueprints
|
||||
and app context. This is why we called <code class="docutils literal notranslate"><span class="pre">celery_app.set_default()</span></code> above.</p>
|
||||
<p>Here’s an example task that adds two numbers together and returns the result.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">celery</span><span class="w"> </span><span class="kn">import</span> <span class="n">shared_task</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">SubdomainDispatcher</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">domain</span><span class="p">,</span> <span class="n">create_app</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">domain</span> <span class="o">=</span> <span class="n">domain</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">create_app</span> <span class="o">=</span> <span class="n">create_app</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">Lock</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">get_application</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">host</span><span class="p">):</span>
|
||||
<span class="n">host</span> <span class="o">=</span> <span class="n">host</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">assert</span> <span class="n">host</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">domain</span><span class="p">),</span> <span class="s1">'Configuration error'</span>
|
||||
<span class="n">subdomain</span> <span class="o">=</span> <span class="n">host</span><span class="p">[:</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">domain</span><span class="p">)]</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span>
|
||||
<span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="p">[</span><span class="n">subdomain</span><span class="p">]</span> <span class="o">=</span> <span class="n">app</span>
|
||||
<span class="k">return</span> <span class="n">app</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="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_application</span><span class="p">(</span><span class="n">environ</span><span class="p">[</span><span class="s1">'HTTP_HOST'</span><span class="p">])</span>
|
||||
<span class="k">return</span> <span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This dispatcher can then be used like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">myapplication</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_app</span><span class="p">,</span> <span class="n">get_user_for_subdomain</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.exceptions</span><span class="w"> </span><span class="kn">import</span> <span class="n">NotFound</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">make_app</span><span class="p">(</span><span class="n">subdomain</span><span class="p">):</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">get_user_for_subdomain</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="c1"># if there is no user for that subdomain we still have</span>
|
||||
<span class="c1"># to return a WSGI application that handles that request.</span>
|
||||
<span class="c1"># We can then just return the NotFound() exception as</span>
|
||||
<span class="c1"># application which will render a default 404 page.</span>
|
||||
<span class="c1"># You might also redirect the user to the main page then</span>
|
||||
<span class="k">return</span> <span class="n">NotFound</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># otherwise create the application for the specific user</span>
|
||||
<span class="k">return</span> <span class="n">create_app</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
||||
|
||||
<span class="n">application</span> <span class="o">=</span> <span class="n">SubdomainDispatcher</span><span class="p">(</span><span class="s1">'example.com'</span><span class="p">,</span> <span class="n">make_app</span><span class="p">)</span>
|
||||
<span class="nd">@shared_task</span><span class="p">(</span><span class="n">ignore_result</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_together</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Earlier, we configured Celery to ignore task results by default. Since we want to know
|
||||
the return value of this task, we set <code class="docutils literal notranslate"><span class="pre">ignore_result=False</span></code>. On the other hand, a task
|
||||
that didn’t need a result, such as sending an email, wouldn’t set this.</p>
|
||||
</section>
|
||||
<section id="dispatch-by-path">
|
||||
<h2>Dispatch by Path<a class="headerlink" href="#dispatch-by-path" title="Link to this heading">¶</a></h2>
|
||||
<p>Dispatching by a path on the URL is very similar. Instead of looking at
|
||||
the <code class="docutils literal notranslate"><span class="pre">Host</span></code> header to figure out the subdomain one simply looks at the
|
||||
request path up to the first slash.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">threading</span><span class="w"> </span><span class="kn">import</span> <span class="n">Lock</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">wsgiref.util</span><span class="w"> </span><span class="kn">import</span> <span class="n">shift_path_info</span>
|
||||
<section id="calling-tasks">
|
||||
<h2>Calling Tasks<a class="headerlink" href="#calling-tasks" title="Link to this heading">¶</a></h2>
|
||||
<p>The decorated function becomes a task object with methods to call it in the background.
|
||||
The simplest way is to use the <code class="docutils literal notranslate"><span class="pre">delay(*args,</span> <span class="pre">**kwargs)</span></code> method. See Celery’s docs for
|
||||
more methods.</p>
|
||||
<p>A Celery worker must be running to run the task. Starting a worker is shown in the
|
||||
previous sections.</p>
|
||||
<div class="highlight-python 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">request</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">PathDispatcher</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">default_app</span><span class="p">,</span> <span class="n">create_app</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">default_app</span> <span class="o">=</span> <span class="n">default_app</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">create_app</span> <span class="o">=</span> <span class="n">create_app</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">Lock</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">get_application</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prefix</span><span class="p">):</span>
|
||||
<span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="p">[</span><span class="n">prefix</span><span class="p">]</span> <span class="o">=</span> <span class="n">app</span>
|
||||
<span class="k">return</span> <span class="n">app</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="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_application</span><span class="p">(</span><span class="n">_peek_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">shift_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_app</span>
|
||||
<span class="k">return</span> <span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_peek_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">):</span>
|
||||
<span class="n">segments</span> <span class="o">=</span> <span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"PATH_INFO"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">lstrip</span><span class="p">(</span><span class="s2">"/"</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">segments</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">segments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/add"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">start_add</span><span class="p">()</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">]:</span>
|
||||
<span class="n">a</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"a"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
|
||||
<span class="n">b</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"b"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">add_together</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">{</span><span class="s2">"result_id"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">id</span><span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The big difference between this and the subdomain one is that this one
|
||||
falls back to another application if the creator function returns <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">myapplication</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_app</span><span class="p">,</span> <span class="n">default_app</span><span class="p">,</span> <span class="n">get_user_for_prefix</span>
|
||||
<p>The route doesn’t get the task’s result immediately. That would defeat the purpose by
|
||||
blocking the response. Instead, we return the running task’s result id, which we can use
|
||||
later to get the result.</p>
|
||||
</section>
|
||||
<section id="getting-results">
|
||||
<h2>Getting Results<a class="headerlink" href="#getting-results" title="Link to this heading">¶</a></h2>
|
||||
<p>To fetch the result of the task we started above, we’ll add another route that takes the
|
||||
result id we returned before. We return whether the task is finished (ready), whether it
|
||||
finished successfully, and what the return value (or error) was if it is finished.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">celery.result</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncResult</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">make_app</span><span class="p">(</span><span class="n">prefix</span><span class="p">):</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">get_user_for_prefix</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">create_app</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/result/<id>"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">task_result</span><span class="p">(</span><span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">]:</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">AsyncResult</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">{</span>
|
||||
<span class="s2">"ready"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">ready</span><span class="p">(),</span>
|
||||
<span class="s2">"successful"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">successful</span><span class="p">(),</span>
|
||||
<span class="s2">"value"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">result</span> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">ready</span><span class="p">()</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now you can start the task using the first route, then poll for the result using the
|
||||
second route. This keeps the Flask request workers from being blocked waiting for tasks
|
||||
to finish.</p>
|
||||
<p>The Flask repository contains <a class="reference external" href="https://github.com/pallets/flask/tree/main/examples/celery">an example</a>
|
||||
using JavaScript to submit tasks and poll for progress and results.</p>
|
||||
</section>
|
||||
<section id="passing-data-to-tasks">
|
||||
<h2>Passing Data to Tasks<a class="headerlink" href="#passing-data-to-tasks" title="Link to this heading">¶</a></h2>
|
||||
<p>The “add” task above took two integers as arguments. To pass arguments to tasks, Celery
|
||||
has to serialize them to a format that it can pass to other processes. Therefore,
|
||||
passing complex objects is not recommended. For example, it would be impossible to pass
|
||||
a SQLAlchemy model object, since that object is probably not serializable and is tied to
|
||||
the session that queried it.</p>
|
||||
<p>Pass the minimal amount of data necessary to fetch or recreate any complex data within
|
||||
the task. Consider a task that will run when the logged in user asks for an archive of
|
||||
their data. The Flask request knows the logged in user, and has the user object queried
|
||||
from the database. It got that by querying the database for a given id, so the task can
|
||||
do the same thing. Pass the user’s id rather than the user object.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@shared_task</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_user_archive</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">user_id</span><span class="p">)</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="n">application</span> <span class="o">=</span> <span class="n">PathDispatcher</span><span class="p">(</span><span class="n">default_app</span><span class="p">,</span> <span class="n">make_app</span><span class="p">)</span>
|
||||
<span class="n">generate_user_archive</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="n">current_user</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -221,20 +247,23 @@ falls back to another application if the creator function returns <code class="d
|
|||
<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="#">Application Dispatching</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-this-document">Working with this Document</a></li>
|
||||
<li><a class="reference internal" href="#combining-applications">Combining Applications</a></li>
|
||||
<li><a class="reference internal" href="#dispatch-by-subdomain">Dispatch by Subdomain</a></li>
|
||||
<li><a class="reference internal" href="#dispatch-by-path">Dispatch by Path</a></li>
|
||||
<li><a class="reference internal" href="#">Background Tasks with Celery</a><ul>
|
||||
<li><a class="reference internal" href="#install">Install</a></li>
|
||||
<li><a class="reference internal" href="#integrate-celery-with-flask">Integrate Celery with Flask</a></li>
|
||||
<li><a class="reference internal" href="#application-factory">Application Factory</a></li>
|
||||
<li><a class="reference internal" href="#defining-tasks">Defining Tasks</a></li>
|
||||
<li><a class="reference internal" href="#calling-tasks">Calling Tasks</a></li>
|
||||
<li><a class="reference internal" href="#getting-results">Getting Results</a></li>
|
||||
<li><a class="reference internal" href="#passing-data-to-tasks">Passing Data to Tasks</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -244,8 +273,8 @@ falls back to another application if the creator function returns <code class="d
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="appfactories.html" title="previous chapter">Application Factories</a>
|
||||
<li>Next: <a href="urlprocessors.html" title="next chapter">Using URL Processors</a></ul>
|
||||
<li>Previous: <a href="requestchecksum.html" title="previous chapter">Request Content Checksums</a>
|
||||
<li>Next: <a href="subclassing.html" title="next chapter">Subclassing Flask</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -269,4 +298,4 @@ falls back to another application if the creator function returns <code class="d
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Application Factories — Flask Documentation (3.2.x)</title>
|
||||
<title>Deferred Request Callbacks — 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="Application Dispatching" href="appdispatch.html" />
|
||||
<link rel="prev" title="Large Applications as Packages" href="packages.html" />
|
||||
<link rel="next" title="Adding HTTP Method Overrides" href="methodoverrides.html" />
|
||||
<link rel="prev" title="Streaming Contents" href="streaming.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,130 +28,62 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="appdispatch.html" title="Application Dispatching"
|
||||
<a href="methodoverrides.html" title="Adding HTTP Method Overrides"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="packages.html" title="Large Applications as Packages"
|
||||
<a href="streaming.html" title="Streaming Contents"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Application Factories</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Deferred Request Callbacks</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="application-factories">
|
||||
<h1>Application Factories<a class="headerlink" href="#application-factories" title="Link to this heading">¶</a></h1>
|
||||
<p>If you are already using packages and blueprints for your application
|
||||
(<a class="reference internal" href="../blueprints.html"><span class="doc">Modular Applications with Blueprints</span></a>) there are a couple of really nice ways to further improve
|
||||
the experience. A common pattern is creating the application object when
|
||||
the blueprint is imported. But if you move the creation of this object
|
||||
into a function, you can then create multiple instances of this app later.</p>
|
||||
<p>So why would you want to do this?</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>Testing. You can have instances of the application with different
|
||||
settings to test every case.</p></li>
|
||||
<li><p>Multiple instances. Imagine you want to run different versions of the
|
||||
same application. Of course you could have multiple instances with
|
||||
different configs set up in your webserver, but if you use factories,
|
||||
you can have multiple instances of the same application running in the
|
||||
same application process which can be handy.</p></li>
|
||||
</ol>
|
||||
<p>So how would you then actually implement that?</p>
|
||||
<section id="basic-factories">
|
||||
<h2>Basic Factories<a class="headerlink" href="#basic-factories" title="Link to this heading">¶</a></h2>
|
||||
<p>The idea is to set up the application in a function. Like this:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">create_app</span><span class="p">(</span><span class="n">config_filename</span><span class="p">):</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">config</span><span class="o">.</span><span class="n">from_pyfile</span><span class="p">(</span><span class="n">config_filename</span><span class="p">)</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">db</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
<section id="deferred-request-callbacks">
|
||||
<h1>Deferred Request Callbacks<a class="headerlink" href="#deferred-request-callbacks" title="Link to this heading">¶</a></h1>
|
||||
<p>One of the design principles of Flask is that response objects are created and
|
||||
passed down a chain of potential callbacks that can modify them or replace
|
||||
them. When the request handling starts, there is no response object yet. It is
|
||||
created as necessary either by a view function or by some other component in
|
||||
the system.</p>
|
||||
<p>What happens if you want to modify the response at a point where the response
|
||||
does not exist yet? A common example for that would be a
|
||||
<a class="reference internal" href="../api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> callback that wants to set a cookie on the
|
||||
response object.</p>
|
||||
<p>One way is to avoid the situation. Very often that is possible. For instance
|
||||
you can try to move that logic into a <a class="reference internal" href="../api.html#flask.Flask.after_request" title="flask.Flask.after_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">after_request()</span></code></a>
|
||||
callback instead. However, sometimes moving code there makes it
|
||||
more complicated or awkward to reason about.</p>
|
||||
<p>As an alternative, you can use <a class="reference internal" href="../api.html#flask.after_this_request" title="flask.after_this_request"><code class="xref py py-func docutils literal notranslate"><span class="pre">after_this_request()</span></code></a> to register
|
||||
callbacks that will execute after only the current request. This way you can
|
||||
defer code execution from anywhere in the application, based on the current
|
||||
request.</p>
|
||||
<p>At any time during a request, we can register a function to be called at the
|
||||
end of the request. For example you can remember the current language of the
|
||||
user in a cookie in a <a class="reference internal" href="../api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> callback:</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">request</span><span class="p">,</span> <span class="n">after_this_request</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.views.admin</span><span class="w"> </span><span class="kn">import</span> <span class="n">admin</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.views.frontend</span><span class="w"> </span><span class="kn">import</span> <span class="n">frontend</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">admin</span><span class="p">)</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">frontend</span><span class="p">)</span>
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">before_request</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">detect_user_language</span><span class="p">():</span>
|
||||
<span class="n">language</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_lang'</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">app</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The downside is that you cannot use the application object in the blueprints
|
||||
at import time. You can however use it from within a request. How do you
|
||||
get access to the application with the config? Use
|
||||
<a class="reference internal" href="../api.html#flask.current_app" title="flask.current_app"><code class="xref py py-data docutils literal notranslate"><span class="pre">current_app</span></code></a>:</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">current_app</span><span class="p">,</span> <span class="n">Blueprint</span><span class="p">,</span> <span class="n">render_template</span>
|
||||
<span class="n">admin</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s1">'admin'</span><span class="p">,</span> <span class="vm">__name__</span><span class="p">,</span> <span class="n">url_prefix</span><span class="o">=</span><span class="s1">'/admin'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">language</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">language</span> <span class="o">=</span> <span class="n">guess_language_from_request</span><span class="p">()</span>
|
||||
|
||||
<span class="nd">@admin</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="n">render_template</span><span class="p">(</span><span class="n">current_app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'INDEX_TEMPLATE'</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we look up the name of a template in the config.</p>
|
||||
</section>
|
||||
<section id="factories-extensions">
|
||||
<h2>Factories & Extensions<a class="headerlink" href="#factories-extensions" title="Link to this heading">¶</a></h2>
|
||||
<p>It’s preferable to create your extensions and app factories so that the
|
||||
extension object does not initially get bound to the application.</p>
|
||||
<p>Using <a class="reference external" href="https://flask-sqlalchemy.palletsprojects.com/">Flask-SQLAlchemy</a>,
|
||||
as an example, you should not do something along those lines:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">create_app</span><span class="p">(</span><span class="n">config_filename</span><span class="p">):</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">config</span><span class="o">.</span><span class="n">from_pyfile</span><span class="p">(</span><span class="n">config_filename</span><span class="p">)</span>
|
||||
<span class="c1"># when the response exists, set a cookie with the language</span>
|
||||
<span class="nd">@after_this_request</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">remember_language</span><span class="p">(</span><span class="n">response</span><span class="p">):</span>
|
||||
<span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span><span class="s1">'user_lang'</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">response</span>
|
||||
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">SQLAlchemy</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">language</span> <span class="o">=</span> <span class="n">language</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>But, rather, in model.py (or equivalent):</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">db</span> <span class="o">=</span> <span class="n">SQLAlchemy</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>and in your application.py (or equivalent):</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">create_app</span><span class="p">(</span><span class="n">config_filename</span><span class="p">):</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">config</span><span class="o">.</span><span class="n">from_pyfile</span><span class="p">(</span><span class="n">config_filename</span><span class="p">)</span>
|
||||
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.model</span><span class="w"> </span><span class="kn">import</span> <span class="n">db</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Using this design pattern, no application-specific state is stored on the
|
||||
extension object, so one extension object can be used for multiple apps.
|
||||
For more information about the design of extensions refer to <a class="reference internal" href="../extensiondev.html"><span class="doc">Flask Extension Development</span></a>.</p>
|
||||
</section>
|
||||
<section id="using-applications">
|
||||
<h2>Using Applications<a class="headerlink" href="#using-applications" title="Link to this heading">¶</a></h2>
|
||||
<p>To run such an application, you can use the <strong class="command">flask</strong> command:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ flask --app hello run
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Flask will automatically detect the factory if it is named
|
||||
<code class="docutils literal notranslate"><span class="pre">create_app</span></code> or <code class="docutils literal notranslate"><span class="pre">make_app</span></code> in <code class="docutils literal notranslate"><span class="pre">hello</span></code>. You can also pass arguments
|
||||
to the factory like this:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ flask --app 'hello:create_app(local_auth=True)' run
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Then the <code class="docutils literal notranslate"><span class="pre">create_app</span></code> factory in <code class="docutils literal notranslate"><span class="pre">hello</span></code> is called with the keyword
|
||||
argument <code class="docutils literal notranslate"><span class="pre">local_auth=True</span></code>. See <a class="reference internal" href="../cli.html"><span class="doc">Command Line Interface</span></a> for more detail.</p>
|
||||
</section>
|
||||
<section id="factory-improvements">
|
||||
<h2>Factory Improvements<a class="headerlink" href="#factory-improvements" title="Link to this heading">¶</a></h2>
|
||||
<p>The factory function above is not very clever, but you can improve it.
|
||||
The following changes are straightforward to implement:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>Make it possible to pass in configuration values for unit tests so that
|
||||
you don’t have to create config files on the filesystem.</p></li>
|
||||
<li><p>Call a function from a blueprint when the application is setting up so
|
||||
that you have a place to modify attributes of the application (like
|
||||
hooking in before/after request handlers etc.)</p></li>
|
||||
<li><p>Add in WSGI middlewares when the application is being created if necessary.</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -162,31 +94,20 @@ hooking in before/after request handlers etc.)</p></li>
|
|||
<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="#">Application Factories</a><ul>
|
||||
<li><a class="reference internal" href="#basic-factories">Basic Factories</a></li>
|
||||
<li><a class="reference internal" href="#factories-extensions">Factories & Extensions</a></li>
|
||||
<li><a class="reference internal" href="#using-applications">Using Applications</a></li>
|
||||
<li><a class="reference internal" href="#factory-improvements">Factory Improvements</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="packages.html" title="previous chapter">Large Applications as Packages</a>
|
||||
<li>Next: <a href="appdispatch.html" title="next chapter">Application Dispatching</a></ul>
|
||||
<li>Previous: <a href="streaming.html" title="previous chapter">Streaming Contents</a>
|
||||
<li>Next: <a href="methodoverrides.html" title="next chapter">Adding HTTP Method Overrides</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -210,4 +131,4 @@ hooking in before/after request handlers etc.)</p></li>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Caching — Flask Documentation (3.2.x)</title>
|
||||
<title>Adding a favicon — 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="View Decorators" href="viewdecorators.html" />
|
||||
<link rel="prev" title="Uploading Files" href="fileuploads.html" />
|
||||
<link rel="next" title="Streaming Contents" href="streaming.html" />
|
||||
<link rel="prev" title="MongoDB with MongoEngine" href="mongoengine.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,33 +28,73 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="viewdecorators.html" title="View Decorators"
|
||||
<a href="streaming.html" title="Streaming Contents"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="fileuploads.html" title="Uploading Files"
|
||||
<a href="mongoengine.html" title="MongoDB with MongoEngine"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Caching</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Adding a favicon</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="caching">
|
||||
<h1>Caching<a class="headerlink" href="#caching" title="Link to this heading">¶</a></h1>
|
||||
<p>When your application runs slow, throw some caches in. Well, at least
|
||||
it’s the easiest way to speed up things. What does a cache do? Say you
|
||||
have a function that takes some time to complete but the results would
|
||||
still be good enough if they were 5 minutes old. So then the idea is that
|
||||
you actually put the result of that calculation into a cache for some
|
||||
time.</p>
|
||||
<p>Flask itself does not provide caching for you, but <a class="reference external" href="https://flask-caching.readthedocs.io/en/latest/">Flask-Caching</a>, an
|
||||
extension for Flask does. Flask-Caching supports various backends, and it is
|
||||
even possible to develop your own caching backend.</p>
|
||||
|
||||
<section id="adding-a-favicon">
|
||||
<h1>Adding a favicon<a class="headerlink" href="#adding-a-favicon" title="Link to this heading">¶</a></h1>
|
||||
<p>A “favicon” is an icon used by browsers for tabs and bookmarks. This helps
|
||||
to distinguish your website and to give it a unique brand.</p>
|
||||
<p>A common question is how to add a favicon to a Flask application. First, of
|
||||
course, you need an icon. It should be 16 × 16 pixels and in the ICO file
|
||||
format. This is not a requirement but a de-facto standard supported by all
|
||||
relevant browsers. Put the icon in your static directory as
|
||||
<code class="file docutils literal notranslate"><span class="pre">favicon.ico</span></code>.</p>
|
||||
<p>Now, to get browsers to find your icon, the correct way is to add a link
|
||||
tag in your HTML. So, for example:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"shortcut icon"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'static'</span><span class="o">,</span> <span class="nv">filename</span><span class="o">=</span><span class="s1">'favicon.ico'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That’s all you need for most browsers, however some really old ones do not
|
||||
support this standard. The old de-facto standard is to serve this file,
|
||||
with this name, at the website root. If your application is not mounted at
|
||||
the root path of the domain you either need to configure the web server to
|
||||
serve the icon at the root or if you can’t do that you’re out of luck. If
|
||||
however your application is the root you can simply route a redirect:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span>
|
||||
<span class="s2">"/favicon.ico"</span><span class="p">,</span>
|
||||
<span class="n">endpoint</span><span class="o">=</span><span class="s2">"favicon"</span><span class="p">,</span>
|
||||
<span class="n">redirect_to</span><span class="o">=</span><span class="n">url_for</span><span class="p">(</span><span class="s2">"static"</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s2">"favicon.ico"</span><span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you want to save the extra redirect request you can also write a view
|
||||
using <a class="reference internal" href="../api.html#flask.send_from_directory" title="flask.send_from_directory"><code class="xref py py-func docutils literal notranslate"><span class="pre">send_from_directory()</span></code></a>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</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">send_from_directory</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/favicon.ico'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">favicon</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">send_from_directory</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">root_path</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">),</span>
|
||||
<span class="s1">'favicon.ico'</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s1">'image/vnd.microsoft.icon'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We can leave out the explicit mimetype and it will be guessed, but we may
|
||||
as well specify it to avoid the extra guessing, as it will always be the
|
||||
same.</p>
|
||||
<p>The above will serve the icon via your application and if possible it’s
|
||||
better to configure your dedicated web server to serve it; refer to the
|
||||
web server’s documentation.</p>
|
||||
<section id="see-also">
|
||||
<h2>See also<a class="headerlink" href="#see-also" title="Link to this heading">¶</a></h2>
|
||||
<ul class="simple">
|
||||
<li><p>The <a class="reference external" href="https://en.wikipedia.org/wiki/Favicon">Favicon</a> article on
|
||||
Wikipedia</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -65,20 +105,28 @@ even possible to develop your own caching backend.</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="#">Adding a favicon</a><ul>
|
||||
<li><a class="reference internal" href="#see-also">See also</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="fileuploads.html" title="previous chapter">Uploading Files</a>
|
||||
<li>Next: <a href="viewdecorators.html" title="next chapter">View Decorators</a></ul>
|
||||
<li>Previous: <a href="mongoengine.html" title="previous chapter">MongoDB with MongoEngine</a>
|
||||
<li>Next: <a href="streaming.html" title="next chapter">Streaming Contents</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -102,4 +150,4 @@ even possible to develop your own caching backend.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Background Tasks with Celery — Flask Documentation (3.2.x)</title>
|
||||
<title>Uploading Files — 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="Subclassing Flask" href="subclassing.html" />
|
||||
<link rel="prev" title="Request Content Checksums" href="requestchecksum.html" />
|
||||
<link rel="next" title="Caching" href="caching.html" />
|
||||
<link rel="prev" title="SQLAlchemy in Flask" href="sqlalchemy.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,214 +28,189 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="subclassing.html" title="Subclassing Flask"
|
||||
<a href="caching.html" title="Caching"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="requestchecksum.html" title="Request Content Checksums"
|
||||
<a href="sqlalchemy.html" title="SQLAlchemy in Flask"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Background Tasks with Celery</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Uploading Files</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="background-tasks-with-celery">
|
||||
<h1>Background Tasks with Celery<a class="headerlink" href="#background-tasks-with-celery" title="Link to this heading">¶</a></h1>
|
||||
<p>If your application has a long running task, such as processing some uploaded data or
|
||||
sending email, you don’t want to wait for it to finish during a request. Instead, use a
|
||||
task queue to send the necessary data to another process that will run the task in the
|
||||
background while the request returns immediately.</p>
|
||||
<p><a class="reference external" href="https://celery.readthedocs.io">Celery</a> is a powerful task queue that can be used for simple background tasks as well
|
||||
as complex multi-stage programs and schedules. This guide will show you how to configure
|
||||
Celery using Flask. Read Celery’s <a class="reference external" href="https://celery.readthedocs.io/en/latest/getting-started/first-steps-with-celery.html">First Steps with Celery</a> guide to learn how to use
|
||||
Celery itself.</p>
|
||||
<p>The Flask repository contains <a class="reference external" href="https://github.com/pallets/flask/tree/main/examples/celery">an example</a>
|
||||
based on the information on this page, which also shows how to use JavaScript to submit
|
||||
tasks and poll for progress and results.</p>
|
||||
<section id="install">
|
||||
<h2>Install<a class="headerlink" href="#install" title="Link to this heading">¶</a></h2>
|
||||
<p>Install Celery from PyPI, for example using pip:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ pip install celery
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="integrate-celery-with-flask">
|
||||
<h2>Integrate Celery with Flask<a class="headerlink" href="#integrate-celery-with-flask" title="Link to this heading">¶</a></h2>
|
||||
<p>You can use Celery without any integration with Flask, but it’s convenient to configure
|
||||
it through Flask’s config, and to let tasks access the Flask application.</p>
|
||||
<p>Celery uses similar ideas to Flask, with a <code class="docutils literal notranslate"><span class="pre">Celery</span></code> app object that has configuration
|
||||
and registers tasks. While creating a Flask app, use the following code to create and
|
||||
configure a Celery app as well.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">celery</span><span class="w"> </span><span class="kn">import</span> <span class="n">Celery</span><span class="p">,</span> <span class="n">Task</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">celery_init_app</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">Flask</span><span class="p">)</span> <span class="o">-></span> <span class="n">Celery</span><span class="p">:</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">FlaskTask</span><span class="p">(</span><span class="n">Task</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="nb">object</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="nb">object</span><span class="p">:</span>
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">app_context</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">run</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>
|
||||
<section id="uploading-files">
|
||||
<h1>Uploading Files<a class="headerlink" href="#uploading-files" title="Link to this heading">¶</a></h1>
|
||||
<p>Ah yes, the good old problem of file uploads. The basic idea of file
|
||||
uploads is actually quite simple. It basically works like this:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre"><form></span></code> tag is marked with <code class="docutils literal notranslate"><span class="pre">enctype=multipart/form-data</span></code>
|
||||
and an <code class="docutils literal notranslate"><span class="pre"><input</span> <span class="pre">type=file></span></code> is placed in that form.</p></li>
|
||||
<li><p>The application accesses the file from the <code class="xref py py-attr docutils literal notranslate"><span class="pre">files</span></code>
|
||||
dictionary on the request object.</p></li>
|
||||
<li><p>use the <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/datastructures/#werkzeug.datastructures.FileStorage.save" title="(in Werkzeug v3.1.x)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> method of the file to save
|
||||
the file permanently somewhere on the filesystem.</p></li>
|
||||
</ol>
|
||||
<section id="a-gentle-introduction">
|
||||
<h2>A Gentle Introduction<a class="headerlink" href="#a-gentle-introduction" title="Link to this heading">¶</a></h2>
|
||||
<p>Let’s start with a very basic application that uploads a file to a
|
||||
specific upload folder and displays a file to the user. Let’s look at the
|
||||
bootstrapping code for our application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</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="p">,</span> <span class="n">flash</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</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">secure_filename</span>
|
||||
|
||||
<span class="n">celery_app</span> <span class="o">=</span> <span class="n">Celery</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">task_cls</span><span class="o">=</span><span class="n">FlaskTask</span><span class="p">)</span>
|
||||
<span class="n">celery_app</span><span class="o">.</span><span class="n">config_from_object</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s2">"CELERY"</span><span class="p">])</span>
|
||||
<span class="n">celery_app</span><span class="o">.</span><span class="n">set_default</span><span class="p">()</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">extensions</span><span class="p">[</span><span class="s2">"celery"</span><span class="p">]</span> <span class="o">=</span> <span class="n">celery_app</span>
|
||||
<span class="k">return</span> <span class="n">celery_app</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This creates and returns a <code class="docutils literal notranslate"><span class="pre">Celery</span></code> app object. Celery <a class="reference external" href="https://celery.readthedocs.io/en/stable/userguide/configuration.html">configuration</a> is taken from
|
||||
the <code class="docutils literal notranslate"><span class="pre">CELERY</span></code> key in the Flask configuration. The Celery app is set as the default, so
|
||||
that it is seen during each request. The <code class="docutils literal notranslate"><span class="pre">Task</span></code> subclass automatically runs task
|
||||
functions with a Flask app context active, so that services like your database
|
||||
connections are available.</p>
|
||||
<p>Here’s a basic <code class="docutils literal notranslate"><span class="pre">example.py</span></code> that configures Celery to use Redis for communication. We
|
||||
enable a result backend, but ignore results by default. This allows us to store results
|
||||
only for tasks where we care about the result.</p>
|
||||
<div class="highlight-python 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">UPLOAD_FOLDER</span> <span class="o">=</span> <span class="s1">'/path/to/the/uploads'</span>
|
||||
<span class="n">ALLOWED_EXTENSIONS</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'txt'</span><span class="p">,</span> <span class="s1">'pdf'</span><span class="p">,</span> <span class="s1">'png'</span><span class="p">,</span> <span class="s1">'jpg'</span><span class="p">,</span> <span class="s1">'jpeg'</span><span class="p">,</span> <span class="s1">'gif'</span><span class="p">}</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">config</span><span class="o">.</span><span class="n">from_mapping</span><span class="p">(</span>
|
||||
<span class="n">CELERY</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span>
|
||||
<span class="n">broker_url</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">result_backend</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">task_ignore_result</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="p">),</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'UPLOAD_FOLDER'</span><span class="p">]</span> <span class="o">=</span> <span class="n">UPLOAD_FOLDER</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So first we need a couple of imports. Most should be straightforward, the
|
||||
<code class="xref py py-func docutils literal notranslate"><span class="pre">werkzeug.secure_filename()</span></code> is explained a little bit later. The
|
||||
<code class="docutils literal notranslate"><span class="pre">UPLOAD_FOLDER</span></code> is where we will store the uploaded files and the
|
||||
<code class="docutils literal notranslate"><span class="pre">ALLOWED_EXTENSIONS</span></code> is the set of allowed file extensions.</p>
|
||||
<p>Why do we limit the extensions that are allowed? You probably don’t want
|
||||
your users to be able to upload everything there if the server is directly
|
||||
sending out the data to the client. That way you can make sure that users
|
||||
are not able to upload HTML files that would cause XSS problems (see
|
||||
<a class="reference internal" href="../web-security.html#security-xss"><span class="std std-ref">Cross-Site Scripting (XSS)</span></a>). Also make sure to disallow <code class="docutils literal notranslate"><span class="pre">.php</span></code> files if the server
|
||||
executes them, but who has PHP installed on their server, right? :)</p>
|
||||
<p>Next the functions that check if an extension is valid and that uploads
|
||||
the file and redirects the user to the URL for the uploaded file:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">allowed_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="s1">'.'</span> <span class="ow">in</span> <span class="n">filename</span> <span class="ow">and</span> \
|
||||
<span class="n">filename</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s1">'.'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="n">ALLOWED_EXTENSIONS</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="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">upload_file</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span>
|
||||
<span class="c1"># check if the post request has the file part</span>
|
||||
<span class="k">if</span> <span class="s1">'file'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span><span class="p">:</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'No file part'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
|
||||
<span class="n">file</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span>
|
||||
<span class="c1"># If the user does not select a file, the browser submits an</span>
|
||||
<span class="c1"># empty file without a filename.</span>
|
||||
<span class="k">if</span> <span class="n">file</span><span class="o">.</span><span class="n">filename</span> <span class="o">==</span> <span class="s1">''</span><span class="p">:</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'No selected file'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">file</span> <span class="ow">and</span> <span class="n">allowed_file</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">filename</span><span class="p">):</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">secure_filename</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span>
|
||||
<span class="n">file</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'UPLOAD_FOLDER'</span><span class="p">],</span> <span class="n">filename</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'download_file'</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">filename</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="s1">'''</span>
|
||||
<span class="s1"> <!doctype html></span>
|
||||
<span class="s1"> <title>Upload new File</title></span>
|
||||
<span class="s1"> <h1>Upload new File</h1></span>
|
||||
<span class="s1"> <form method=post enctype=multipart/form-data></span>
|
||||
<span class="s1"> <input type=file name=file></span>
|
||||
<span class="s1"> <input type=submit value=Upload></span>
|
||||
<span class="s1"> </form></span>
|
||||
<span class="s1"> '''</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So what does that <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/utils/#werkzeug.utils.secure_filename" title="(in Werkzeug v3.1.x)"><code class="xref py py-func docutils literal notranslate"><span class="pre">secure_filename()</span></code></a> function actually do?
|
||||
Now the problem is that there is that principle called “never trust user
|
||||
input”. This is also true for the filename of an uploaded file. All
|
||||
submitted form data can be forged, and filenames can be dangerous. For
|
||||
the moment just remember: always use that function to secure a filename
|
||||
before storing it directly on the filesystem.</p>
|
||||
<div class="admonition-information-for-the-pros admonition">
|
||||
<p class="admonition-title">Information for the Pros</p>
|
||||
<p>So you’re interested in what that <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/utils/#werkzeug.utils.secure_filename" title="(in Werkzeug v3.1.x)"><code class="xref py py-func docutils literal notranslate"><span class="pre">secure_filename()</span></code></a>
|
||||
function does and what the problem is if you’re not using it? So just
|
||||
imagine someone would send the following information as <code class="code docutils literal notranslate"><span class="pre">filename</span></code> to
|
||||
your application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">filename</span> <span class="o">=</span> <span class="s2">"../../../../home/username/.bashrc"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Assuming the number of <code class="docutils literal notranslate"><span class="pre">../</span></code> is correct and you would join this with
|
||||
the <code class="docutils literal notranslate"><span class="pre">UPLOAD_FOLDER</span></code> the user might have the ability to modify a file on
|
||||
the server’s filesystem he or she should not modify. This does require some
|
||||
knowledge about how the application looks like, but trust me, hackers
|
||||
are patient :)</p>
|
||||
<p>Now let’s look how that function works:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">secure_filename</span><span class="p">(</span><span class="s1">'../../../../home/username/.bashrc'</span><span class="p">)</span>
|
||||
<span class="go">'home_username_.bashrc'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>We want to be able to serve the uploaded files so they can be downloaded
|
||||
by users. We’ll define a <code class="docutils literal notranslate"><span class="pre">download_file</span></code> view to serve files in the
|
||||
upload folder by name. <code class="docutils literal notranslate"><span class="pre">url_for("download_file",</span> <span class="pre">name=name)</span></code> generates
|
||||
download URLs.</p>
|
||||
<div class="highlight-python 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">send_from_directory</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/uploads/<name>'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">download_file</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">send_from_directory</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s2">"UPLOAD_FOLDER"</span><span class="p">],</span> <span class="n">name</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you’re using middleware or the HTTP server to serve files, you can
|
||||
register the <code class="docutils literal notranslate"><span class="pre">download_file</span></code> endpoint as <code class="docutils literal notranslate"><span class="pre">build_only</span></code> so <code class="docutils literal notranslate"><span class="pre">url_for</span></code>
|
||||
will work without a view function.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span>
|
||||
<span class="s2">"/uploads/<name>"</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="s2">"download_file"</span><span class="p">,</span> <span class="n">build_only</span><span class="o">=</span><span class="kc">True</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">celery_app</span> <span class="o">=</span> <span class="n">celery_init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Point the <code class="docutils literal notranslate"><span class="pre">celery</span> <span class="pre">worker</span></code> command at this and it will find the <code class="docutils literal notranslate"><span class="pre">celery_app</span></code> object.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ celery -A example worker --loglevel INFO
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also run the <code class="docutils literal notranslate"><span class="pre">celery</span> <span class="pre">beat</span></code> command to run tasks on a schedule. See Celery’s
|
||||
docs for more information about defining schedules.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ celery -A example beat --loglevel INFO
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="application-factory">
|
||||
<h2>Application Factory<a class="headerlink" href="#application-factory" title="Link to this heading">¶</a></h2>
|
||||
<p>When using the Flask application factory pattern, call the <code class="docutils literal notranslate"><span class="pre">celery_init_app</span></code> function
|
||||
inside the factory. It sets <code class="docutils literal notranslate"><span class="pre">app.extensions["celery"]</span></code> to the Celery app object, which
|
||||
can be used to get the Celery app from the Flask app returned by the factory.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">create_app</span><span class="p">()</span> <span class="o">-></span> <span class="n">Flask</span><span class="p">:</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">config</span><span class="o">.</span><span class="n">from_mapping</span><span class="p">(</span>
|
||||
<span class="n">CELERY</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span>
|
||||
<span class="n">broker_url</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">result_backend</span><span class="o">=</span><span class="s2">"redis://localhost"</span><span class="p">,</span>
|
||||
<span class="n">task_ignore_result</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||||
<span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_prefixed_env</span><span class="p">()</span>
|
||||
<span class="n">celery_init_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">app</span>
|
||||
</pre></div>
|
||||
<section id="improving-uploads">
|
||||
<h2>Improving Uploads<a class="headerlink" href="#improving-uploads" title="Link to this heading">¶</a></h2>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.6.</span></p>
|
||||
</div>
|
||||
<p>To use <code class="docutils literal notranslate"><span class="pre">celery</span></code> commands, Celery needs an app object, but that’s no longer directly
|
||||
available. Create a <code class="docutils literal notranslate"><span class="pre">make_celery.py</span></code> file that calls the Flask app factory and gets
|
||||
the Celery app from the returned Flask app.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">example</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_app</span>
|
||||
</details><p>So how exactly does Flask handle uploads? Well it will store them in the
|
||||
webserver’s memory if the files are reasonably small, otherwise in a
|
||||
temporary location (as returned by <a class="reference external" href="https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">tempfile.gettempdir()</span></code></a>). But how
|
||||
do you specify the maximum file size after which an upload is aborted? By
|
||||
default Flask will happily accept file uploads with an unlimited amount of
|
||||
memory, but you can limit that by setting the <code class="docutils literal notranslate"><span class="pre">MAX_CONTENT_LENGTH</span></code>
|
||||
config key:</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="p">,</span> <span class="n">Request</span>
|
||||
|
||||
<span class="n">flask_app</span> <span class="o">=</span> <span class="n">create_app</span><span class="p">()</span>
|
||||
<span class="n">celery_app</span> <span class="o">=</span> <span class="n">flask_app</span><span class="o">.</span><span class="n">extensions</span><span class="p">[</span><span class="s2">"celery"</span><span class="p">]</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">config</span><span class="p">[</span><span class="s1">'MAX_CONTENT_LENGTH'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">16</span> <span class="o">*</span> <span class="mi">1000</span> <span class="o">*</span> <span class="mi">1000</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Point the <code class="docutils literal notranslate"><span class="pre">celery</span></code> command to this file.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ celery -A make_celery worker --loglevel INFO
|
||||
$ celery -A make_celery beat --loglevel INFO
|
||||
</pre></div>
|
||||
<p>The code above will limit the maximum allowed payload to 16 megabytes.
|
||||
If a larger file is transmitted, Flask will raise a
|
||||
<a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/exceptions/#werkzeug.exceptions.RequestEntityTooLarge" title="(in Werkzeug v3.1.x)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">RequestEntityTooLarge</span></code></a> exception.</p>
|
||||
<div class="admonition-connection-reset-issue admonition">
|
||||
<p class="admonition-title">Connection Reset Issue</p>
|
||||
<p>When using the local development server, you may get a connection
|
||||
reset error instead of a 413 response. You will get the correct
|
||||
status response when running the app with a production WSGI server.</p>
|
||||
</div>
|
||||
<p>This feature was added in Flask 0.6 but can be achieved in older versions
|
||||
as well by subclassing the request object. For more information on that
|
||||
consult the Werkzeug documentation on file handling.</p>
|
||||
</section>
|
||||
<section id="defining-tasks">
|
||||
<h2>Defining Tasks<a class="headerlink" href="#defining-tasks" title="Link to this heading">¶</a></h2>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">@celery_app.task</span></code> to decorate task functions requires access to the
|
||||
<code class="docutils literal notranslate"><span class="pre">celery_app</span></code> object, which won’t be available when using the factory pattern. It also
|
||||
means that the decorated tasks are tied to the specific Flask and Celery app instances,
|
||||
which could be an issue during testing if you change configuration for a test.</p>
|
||||
<p>Instead, use Celery’s <code class="docutils literal notranslate"><span class="pre">@shared_task</span></code> decorator. This creates task objects that will
|
||||
access whatever the “current app” is, which is a similar concept to Flask’s blueprints
|
||||
and app context. This is why we called <code class="docutils literal notranslate"><span class="pre">celery_app.set_default()</span></code> above.</p>
|
||||
<p>Here’s an example task that adds two numbers together and returns the result.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">celery</span><span class="w"> </span><span class="kn">import</span> <span class="n">shared_task</span>
|
||||
|
||||
<span class="nd">@shared_task</span><span class="p">(</span><span class="n">ignore_result</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_together</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Earlier, we configured Celery to ignore task results by default. Since we want to know
|
||||
the return value of this task, we set <code class="docutils literal notranslate"><span class="pre">ignore_result=False</span></code>. On the other hand, a task
|
||||
that didn’t need a result, such as sending an email, wouldn’t set this.</p>
|
||||
<section id="upload-progress-bars">
|
||||
<h2>Upload Progress Bars<a class="headerlink" href="#upload-progress-bars" title="Link to this heading">¶</a></h2>
|
||||
<p>A while ago many developers had the idea to read the incoming file in
|
||||
small chunks and store the upload progress in the database to be able to
|
||||
poll the progress with JavaScript from the client. The client asks the
|
||||
server every 5 seconds how much it has transmitted, but this is
|
||||
something it should already know.</p>
|
||||
</section>
|
||||
<section id="calling-tasks">
|
||||
<h2>Calling Tasks<a class="headerlink" href="#calling-tasks" title="Link to this heading">¶</a></h2>
|
||||
<p>The decorated function becomes a task object with methods to call it in the background.
|
||||
The simplest way is to use the <code class="docutils literal notranslate"><span class="pre">delay(*args,</span> <span class="pre">**kwargs)</span></code> method. See Celery’s docs for
|
||||
more methods.</p>
|
||||
<p>A Celery worker must be running to run the task. Starting a worker is shown in the
|
||||
previous sections.</p>
|
||||
<div class="highlight-python 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">request</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/add"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">start_add</span><span class="p">()</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">]:</span>
|
||||
<span class="n">a</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"a"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
|
||||
<span class="n">b</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"b"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">add_together</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">{</span><span class="s2">"result_id"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">id</span><span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The route doesn’t get the task’s result immediately. That would defeat the purpose by
|
||||
blocking the response. Instead, we return the running task’s result id, which we can use
|
||||
later to get the result.</p>
|
||||
</section>
|
||||
<section id="getting-results">
|
||||
<h2>Getting Results<a class="headerlink" href="#getting-results" title="Link to this heading">¶</a></h2>
|
||||
<p>To fetch the result of the task we started above, we’ll add another route that takes the
|
||||
result id we returned before. We return whether the task is finished (ready), whether it
|
||||
finished successfully, and what the return value (or error) was if it is finished.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">celery.result</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncResult</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/result/<id>"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">task_result</span><span class="p">(</span><span class="nb">id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">]:</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">AsyncResult</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">{</span>
|
||||
<span class="s2">"ready"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">ready</span><span class="p">(),</span>
|
||||
<span class="s2">"successful"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">successful</span><span class="p">(),</span>
|
||||
<span class="s2">"value"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">result</span> <span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">ready</span><span class="p">()</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now you can start the task using the first route, then poll for the result using the
|
||||
second route. This keeps the Flask request workers from being blocked waiting for tasks
|
||||
to finish.</p>
|
||||
<p>The Flask repository contains <a class="reference external" href="https://github.com/pallets/flask/tree/main/examples/celery">an example</a>
|
||||
using JavaScript to submit tasks and poll for progress and results.</p>
|
||||
</section>
|
||||
<section id="passing-data-to-tasks">
|
||||
<h2>Passing Data to Tasks<a class="headerlink" href="#passing-data-to-tasks" title="Link to this heading">¶</a></h2>
|
||||
<p>The “add” task above took two integers as arguments. To pass arguments to tasks, Celery
|
||||
has to serialize them to a format that it can pass to other processes. Therefore,
|
||||
passing complex objects is not recommended. For example, it would be impossible to pass
|
||||
a SQLAlchemy model object, since that object is probably not serializable and is tied to
|
||||
the session that queried it.</p>
|
||||
<p>Pass the minimal amount of data necessary to fetch or recreate any complex data within
|
||||
the task. Consider a task that will run when the logged in user asks for an archive of
|
||||
their data. The Flask request knows the logged in user, and has the user object queried
|
||||
from the database. It got that by querying the database for a given id, so the task can
|
||||
do the same thing. Pass the user’s id rather than the user object.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@shared_task</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_user_archive</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">user_id</span><span class="p">)</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="n">generate_user_archive</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="n">current_user</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="an-easier-solution">
|
||||
<h2>An Easier Solution<a class="headerlink" href="#an-easier-solution" title="Link to this heading">¶</a></h2>
|
||||
<p>Now there are better solutions that work faster and are more reliable. There
|
||||
are JavaScript libraries like <a class="reference external" href="https://jquery.com/">jQuery</a> that have form plugins to ease the
|
||||
construction of progress bar.</p>
|
||||
<p>Because the common pattern for file uploads exists almost unchanged in all
|
||||
applications dealing with uploads, there are also some Flask extensions that
|
||||
implement a full fledged upload mechanism that allows controlling which
|
||||
file extensions are allowed to be uploaded.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -247,23 +222,20 @@ do the same thing. Pass the user’s id rather than the user object.</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="#">Background Tasks with Celery</a><ul>
|
||||
<li><a class="reference internal" href="#install">Install</a></li>
|
||||
<li><a class="reference internal" href="#integrate-celery-with-flask">Integrate Celery with Flask</a></li>
|
||||
<li><a class="reference internal" href="#application-factory">Application Factory</a></li>
|
||||
<li><a class="reference internal" href="#defining-tasks">Defining Tasks</a></li>
|
||||
<li><a class="reference internal" href="#calling-tasks">Calling Tasks</a></li>
|
||||
<li><a class="reference internal" href="#getting-results">Getting Results</a></li>
|
||||
<li><a class="reference internal" href="#passing-data-to-tasks">Passing Data to Tasks</a></li>
|
||||
<li><a class="reference internal" href="#">Uploading Files</a><ul>
|
||||
<li><a class="reference internal" href="#a-gentle-introduction">A Gentle Introduction</a></li>
|
||||
<li><a class="reference internal" href="#improving-uploads">Improving Uploads</a></li>
|
||||
<li><a class="reference internal" href="#upload-progress-bars">Upload Progress Bars</a></li>
|
||||
<li><a class="reference internal" href="#an-easier-solution">An Easier Solution</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -273,8 +245,8 @@ do the same thing. Pass the user’s id rather than the user object.</p>
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="requestchecksum.html" title="previous chapter">Request Content Checksums</a>
|
||||
<li>Next: <a href="subclassing.html" title="next chapter">Subclassing Flask</a></ul>
|
||||
<li>Previous: <a href="sqlalchemy.html" title="previous chapter">SQLAlchemy in Flask</a>
|
||||
<li>Next: <a href="caching.html" title="next chapter">Caching</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -298,4 +270,4 @@ do the same thing. Pass the user’s id rather than the user object.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Deferred Request Callbacks — Flask Documentation (3.2.x)</title>
|
||||
<title>Message Flashing — 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="Adding HTTP Method Overrides" href="methodoverrides.html" />
|
||||
<link rel="prev" title="Streaming Contents" href="streaming.html" />
|
||||
<link rel="next" title="JavaScript, fetch, and JSON" href="javascript.html" />
|
||||
<link rel="prev" title="Template Inheritance" href="templateinheritance.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,62 +28,161 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="methodoverrides.html" title="Adding HTTP Method Overrides"
|
||||
<a href="javascript.html" title="JavaScript, fetch, and JSON"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="streaming.html" title="Streaming Contents"
|
||||
<a href="templateinheritance.html" title="Template Inheritance"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Deferred Request Callbacks</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Message Flashing</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="deferred-request-callbacks">
|
||||
<h1>Deferred Request Callbacks<a class="headerlink" href="#deferred-request-callbacks" title="Link to this heading">¶</a></h1>
|
||||
<p>One of the design principles of Flask is that response objects are created and
|
||||
passed down a chain of potential callbacks that can modify them or replace
|
||||
them. When the request handling starts, there is no response object yet. It is
|
||||
created as necessary either by a view function or by some other component in
|
||||
the system.</p>
|
||||
<p>What happens if you want to modify the response at a point where the response
|
||||
does not exist yet? A common example for that would be a
|
||||
<a class="reference internal" href="../api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> callback that wants to set a cookie on the
|
||||
response object.</p>
|
||||
<p>One way is to avoid the situation. Very often that is possible. For instance
|
||||
you can try to move that logic into a <a class="reference internal" href="../api.html#flask.Flask.after_request" title="flask.Flask.after_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">after_request()</span></code></a>
|
||||
callback instead. However, sometimes moving code there makes it
|
||||
more complicated or awkward to reason about.</p>
|
||||
<p>As an alternative, you can use <a class="reference internal" href="../api.html#flask.after_this_request" title="flask.after_this_request"><code class="xref py py-func docutils literal notranslate"><span class="pre">after_this_request()</span></code></a> to register
|
||||
callbacks that will execute after only the current request. This way you can
|
||||
defer code execution from anywhere in the application, based on the current
|
||||
request.</p>
|
||||
<p>At any time during a request, we can register a function to be called at the
|
||||
end of the request. For example you can remember the current language of the
|
||||
user in a cookie in a <a class="reference internal" href="../api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> callback:</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">request</span><span class="p">,</span> <span class="n">after_this_request</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">before_request</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">detect_user_language</span><span class="p">():</span>
|
||||
<span class="n">language</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_lang'</span><span class="p">)</span>
|
||||
<section id="message-flashing">
|
||||
<h1>Message Flashing<a class="headerlink" href="#message-flashing" title="Link to this heading">¶</a></h1>
|
||||
<p>Good applications and user interfaces are all about feedback. If the user
|
||||
does not get enough feedback they will probably end up hating the
|
||||
application. Flask provides a really simple way to give feedback to a
|
||||
user with the flashing system. The flashing system basically makes it
|
||||
possible to record a message at the end of a request and access it next
|
||||
request and only next request. This is usually combined with a layout
|
||||
template that does this. Note that browsers and sometimes web servers enforce
|
||||
a limit on cookie sizes. This means that flashing messages that are too
|
||||
large for session cookies causes message flashing to fail silently.</p>
|
||||
<section id="simple-flashing">
|
||||
<h2>Simple Flashing<a class="headerlink" href="#simple-flashing" title="Link to this heading">¶</a></h2>
|
||||
<p>So here is a full example:</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="p">,</span> <span class="n">flash</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">render_template</span><span class="p">,</span> \
|
||||
<span class="n">request</span><span class="p">,</span> <span class="n">url_for</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">language</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">language</span> <span class="o">=</span> <span class="n">guess_language_from_request</span><span class="p">()</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">secret_key</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">'_5#y2L"F4Q8z</span><span class="se">\n\xec</span><span class="s1">]/'</span>
|
||||
|
||||
<span class="c1"># when the response exists, set a cookie with the language</span>
|
||||
<span class="nd">@after_this_request</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">remember_language</span><span class="p">(</span><span class="n">response</span><span class="p">):</span>
|
||||
<span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span><span class="s1">'user_lang'</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">response</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="n">render_template</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">)</span>
|
||||
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">language</span> <span class="o">=</span> <span class="n">language</span>
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/login'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">login</span><span class="p">():</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">'username'</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">'admin'</span> <span class="ow">or</span> \
|
||||
<span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">'password'</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">'secret'</span><span class="p">:</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="s1">'Invalid credentials'</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'You were successfully logged in'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'index'</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">'login.html'</span><span class="p">,</span> <span class="n">error</span><span class="o">=</span><span class="n">error</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And here is the <code class="file docutils literal notranslate"><span class="pre">layout.html</span></code> template which does the magic:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp"><!doctype html></span>
|
||||
<span class="p"><</span><span class="nt">title</span><span class="p">></span>My Application<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">with</span> <span class="nv">messages</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">()</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">flashes</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">message</span> <span class="k">in</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">message</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here is the <code class="file docutils literal notranslate"><span class="pre">index.html</span></code> template which inherits from <code class="file docutils literal notranslate"><span class="pre">layout.html</span></code>:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Overview<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Do you want to <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'login'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>log in?<span class="p"></</span><span class="nt">a</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And here is the <code class="file docutils literal notranslate"><span class="pre">login.html</span></code> template which also inherits from
|
||||
<code class="file docutils literal notranslate"><span class="pre">layout.html</span></code>:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Login<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">error</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">error</span><span class="p">><</span><span class="nt">strong</span><span class="p">></span>Error:<span class="p"></</span><span class="nt">strong</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">error</span> <span class="cp">}}</span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">post</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dt</span><span class="p">></span>Username:
|
||||
<span class="p"><</span><span class="nt">dd</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">text</span> <span class="na">name</span><span class="o">=</span><span class="s">username</span> <span class="na">value</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span>
|
||||
<span class="nv">request.form.username</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dt</span><span class="p">></span>Password:
|
||||
<span class="p"><</span><span class="nt">dd</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">password</span> <span class="na">name</span><span class="o">=</span><span class="s">password</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">submit</span> <span class="na">value</span><span class="o">=</span><span class="s">Login</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="flashing-with-categories">
|
||||
<h2>Flashing With Categories<a class="headerlink" href="#flashing-with-categories" title="Link to this heading">¶</a></h2>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.3.</span></p>
|
||||
</div>
|
||||
</details><p>It is also possible to provide categories when flashing a message. The
|
||||
default category if nothing is provided is <code class="docutils literal notranslate"><span class="pre">'message'</span></code>. Alternative
|
||||
categories can be used to give the user better feedback. For example
|
||||
error messages could be displayed with a red background.</p>
|
||||
<p>To flash a message with a different category, just use the second argument
|
||||
to the <a class="reference internal" href="../api.html#flask.flash" title="flask.flash"><code class="xref py py-func docutils literal notranslate"><span class="pre">flash()</span></code></a> function:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">flash</span><span class="p">(</span><span class="s1">'Invalid password provided'</span><span class="p">,</span> <span class="s1">'error'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Inside the template you then have to tell the
|
||||
<a class="reference internal" href="../api.html#flask.get_flashed_messages" title="flask.get_flashed_messages"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_flashed_messages()</span></code></a> function to also return the
|
||||
categories. The loop looks slightly different in that situation then:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">with</span> <span class="nv">messages</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">(</span><span class="nv">with_categories</span><span class="o">=</span><span class="kp">true</span><span class="o">)</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">flashes</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">category</span><span class="o">,</span> <span class="nv">message</span> <span class="k">in</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">category</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">message</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is just one example of how to render these flashed messages. One
|
||||
might also use the category to add a prefix such as
|
||||
<code class="docutils literal notranslate"><span class="pre"><strong>Error:</strong></span></code> to the message.</p>
|
||||
</section>
|
||||
<section id="filtering-flash-messages">
|
||||
<h2>Filtering Flash Messages<a class="headerlink" href="#filtering-flash-messages" title="Link to this heading">¶</a></h2>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.9.</span></p>
|
||||
</div>
|
||||
</details><p>Optionally you can pass a list of categories which filters the results of
|
||||
<a class="reference internal" href="../api.html#flask.get_flashed_messages" title="flask.get_flashed_messages"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_flashed_messages()</span></code></a>. This is useful if you wish to
|
||||
render each category in a separate block.</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">with</span> <span class="nv">errors</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">(</span><span class="nv">category_filter</span><span class="o">=[</span><span class="s2">"error"</span><span class="o">])</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"alert-message block-message error"</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">"close"</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span>×<span class="p"></</span><span class="nt">a</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span>- <span class="k">for</span> <span class="nv">msg</span> <span class="k">in</span> <span class="nv">errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">msg</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> -<span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -94,20 +193,30 @@ user in a cookie in a <a class="reference internal" href="../api.html#flask.Flas
|
|||
<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="#">Message Flashing</a><ul>
|
||||
<li><a class="reference internal" href="#simple-flashing">Simple Flashing</a></li>
|
||||
<li><a class="reference internal" href="#flashing-with-categories">Flashing With Categories</a></li>
|
||||
<li><a class="reference internal" href="#filtering-flash-messages">Filtering Flash Messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="streaming.html" title="previous chapter">Streaming Contents</a>
|
||||
<li>Next: <a href="methodoverrides.html" title="next chapter">Adding HTTP Method Overrides</a></ul>
|
||||
<li>Previous: <a href="templateinheritance.html" title="previous chapter">Template Inheritance</a>
|
||||
<li>Next: <a href="javascript.html" title="next chapter">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -131,4 +240,4 @@ user in a cookie in a <a class="reference internal" href="../api.html#flask.Flas
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Adding a favicon — Flask Documentation (3.2.x)</title>
|
||||
<title>Patterns for 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>
|
||||
|
|
@ -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="Streaming Contents" href="streaming.html" />
|
||||
<link rel="prev" title="MongoDB with MongoEngine" href="mongoengine.html" />
|
||||
<link rel="next" title="Large Applications as Packages" href="packages.html" />
|
||||
<link rel="prev" title="Working with the Shell" href="../shell.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,73 +28,153 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="streaming.html" title="Streaming Contents"
|
||||
<a href="packages.html" title="Large Applications as Packages"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="mongoengine.html" title="MongoDB with MongoEngine"
|
||||
<a href="../shell.html" title="Working with the Shell"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Adding a favicon</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Patterns for Flask</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="adding-a-favicon">
|
||||
<h1>Adding a favicon<a class="headerlink" href="#adding-a-favicon" title="Link to this heading">¶</a></h1>
|
||||
<p>A “favicon” is an icon used by browsers for tabs and bookmarks. This helps
|
||||
to distinguish your website and to give it a unique brand.</p>
|
||||
<p>A common question is how to add a favicon to a Flask application. First, of
|
||||
course, you need an icon. It should be 16 × 16 pixels and in the ICO file
|
||||
format. This is not a requirement but a de-facto standard supported by all
|
||||
relevant browsers. Put the icon in your static directory as
|
||||
<code class="file docutils literal notranslate"><span class="pre">favicon.ico</span></code>.</p>
|
||||
<p>Now, to get browsers to find your icon, the correct way is to add a link
|
||||
tag in your HTML. So, for example:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"shortcut icon"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'static'</span><span class="o">,</span> <span class="nv">filename</span><span class="o">=</span><span class="s1">'favicon.ico'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That’s all you need for most browsers, however some really old ones do not
|
||||
support this standard. The old de-facto standard is to serve this file,
|
||||
with this name, at the website root. If your application is not mounted at
|
||||
the root path of the domain you either need to configure the web server to
|
||||
serve the icon at the root or if you can’t do that you’re out of luck. If
|
||||
however your application is the root you can simply route a redirect:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span>
|
||||
<span class="s2">"/favicon.ico"</span><span class="p">,</span>
|
||||
<span class="n">endpoint</span><span class="o">=</span><span class="s2">"favicon"</span><span class="p">,</span>
|
||||
<span class="n">redirect_to</span><span class="o">=</span><span class="n">url_for</span><span class="p">(</span><span class="s2">"static"</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s2">"favicon.ico"</span><span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you want to save the extra redirect request you can also write a view
|
||||
using <a class="reference internal" href="../api.html#flask.send_from_directory" title="flask.send_from_directory"><code class="xref py py-func docutils literal notranslate"><span class="pre">send_from_directory()</span></code></a>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</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">send_from_directory</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/favicon.ico'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">favicon</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">send_from_directory</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">root_path</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">),</span>
|
||||
<span class="s1">'favicon.ico'</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s1">'image/vnd.microsoft.icon'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We can leave out the explicit mimetype and it will be guessed, but we may
|
||||
as well specify it to avoid the extra guessing, as it will always be the
|
||||
same.</p>
|
||||
<p>The above will serve the icon via your application and if possible it’s
|
||||
better to configure your dedicated web server to serve it; refer to the
|
||||
web server’s documentation.</p>
|
||||
<section id="see-also">
|
||||
<h2>See also<a class="headerlink" href="#see-also" title="Link to this heading">¶</a></h2>
|
||||
<ul class="simple">
|
||||
<li><p>The <a class="reference external" href="https://en.wikipedia.org/wiki/Favicon">Favicon</a> article on
|
||||
Wikipedia</p></li>
|
||||
<section id="patterns-for-flask">
|
||||
<h1>Patterns for Flask<a class="headerlink" href="#patterns-for-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>Certain features and interactions are common enough that you will find
|
||||
them in most web applications. For example, many applications use a
|
||||
relational database and user authentication. They will open a database
|
||||
connection at the beginning of the request and get the information for
|
||||
the logged in user. At the end of the request, the database connection
|
||||
is closed.</p>
|
||||
<p>These types of patterns may be a bit outside the scope of Flask itself,
|
||||
but Flask makes it easy to implement them. Some common patterns are
|
||||
collected in the following pages.</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="packages.html">Large Applications as Packages</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="packages.html#simple-packages">Simple Packages</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="packages.html#working-with-blueprints">Working with Blueprints</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="appfactories.html">Application Factories</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#basic-factories">Basic Factories</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#factories-extensions">Factories & Extensions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#using-applications">Using Applications</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#factory-improvements">Factory Improvements</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="appdispatch.html">Application Dispatching</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#working-with-this-document">Working with this Document</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#combining-applications">Combining Applications</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#dispatch-by-subdomain">Dispatch by Subdomain</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#dispatch-by-path">Dispatch by Path</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="urlprocessors.html">Using URL Processors</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="urlprocessors.html#internationalized-application-urls">Internationalized Application URLs</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="urlprocessors.html#internationalized-blueprint-urls">Internationalized Blueprint URLs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="sqlite3.html">Using SQLite 3 with Flask</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#connect-on-demand">Connect on Demand</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#easy-querying">Easy Querying</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#initial-schemas">Initial Schemas</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="sqlalchemy.html">SQLAlchemy in Flask</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#flask-sqlalchemy-extension">Flask-SQLAlchemy Extension</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#declarative">Declarative</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#manual-object-relational-mapping">Manual Object Relational Mapping</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#sql-abstraction-layer">SQL Abstraction Layer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="fileuploads.html">Uploading Files</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#a-gentle-introduction">A Gentle Introduction</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#improving-uploads">Improving Uploads</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#upload-progress-bars">Upload Progress Bars</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#an-easier-solution">An Easier Solution</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="caching.html">Caching</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="viewdecorators.html">View Decorators</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#login-required-decorator">Login Required Decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#caching-decorator">Caching Decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#templating-decorator">Templating Decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#endpoint-decorator">Endpoint Decorator</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="wtforms.html">Form Validation with WTForms</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="wtforms.html#the-forms">The Forms</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="wtforms.html#in-the-view">In the View</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="wtforms.html#forms-in-templates">Forms in Templates</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="templateinheritance.html">Template Inheritance</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="templateinheritance.html#base-template">Base Template</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="templateinheritance.html#child-template">Child Template</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="flashing.html">Message Flashing</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="flashing.html#simple-flashing">Simple Flashing</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="flashing.html#flashing-with-categories">Flashing With Categories</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="flashing.html#filtering-flash-messages">Filtering Flash Messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="javascript.html">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#rendering-templates">Rendering Templates</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#generating-urls">Generating URLs</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#making-a-request-with-fetch">Making a Request with <code class="docutils literal notranslate"><span class="pre">fetch</span></code></a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#following-redirects">Following Redirects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#replacing-content">Replacing Content</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#return-json-from-views">Return JSON from Views</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#receiving-json-in-views">Receiving JSON in Views</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="lazyloading.html">Lazily Loading Views</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="lazyloading.html#converting-to-centralized-url-map">Converting to Centralized URL Map</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="lazyloading.html#loading-late">Loading Late</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="mongoengine.html">MongoDB with MongoEngine</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#configuration">Configuration</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#mapping-documents">Mapping Documents</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#creating-data">Creating Data</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#queries">Queries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#documentation">Documentation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="favicon.html">Adding a favicon</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="favicon.html#see-also">See also</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="streaming.html">Streaming Contents</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="streaming.html#basic-usage">Basic Usage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="streaming.html#streaming-from-templates">Streaming from Templates</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="streaming.html#streaming-with-context">Streaming with Context</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="deferredcallbacks.html">Deferred Request Callbacks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="methodoverrides.html">Adding HTTP Method Overrides</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="requestchecksum.html">Request Content Checksums</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="celery.html">Background Tasks with Celery</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#install">Install</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#integrate-celery-with-flask">Integrate Celery with Flask</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#application-factory">Application Factory</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#defining-tasks">Defining Tasks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#calling-tasks">Calling Tasks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#getting-results">Getting Results</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#passing-data-to-tasks">Passing Data to Tasks</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="subclassing.html">Subclassing Flask</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="singlepageapplications.html">Single-Page Applications</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -105,29 +185,18 @@ Wikipedia</p></li>
|
|||
<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="#">Adding a favicon</a><ul>
|
||||
<li><a class="reference internal" href="#see-also">See also</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="mongoengine.html" title="previous chapter">MongoDB with MongoEngine</a>
|
||||
<li>Next: <a href="streaming.html" title="next chapter">Streaming Contents</a></ul>
|
||||
</li>
|
||||
<li>Previous: <a href="../shell.html" title="previous chapter">Working with the Shell</a>
|
||||
<li>Next: <a href="packages.html" title="next chapter">Large Applications as Packages</a>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -150,4 +219,4 @@ Wikipedia</p></li>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Uploading Files — Flask Documentation (3.2.x)</title>
|
||||
<title>JavaScript, fetch, and JSON — 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="Caching" href="caching.html" />
|
||||
<link rel="prev" title="SQLAlchemy in Flask" href="sqlalchemy.html" />
|
||||
<link rel="next" title="Lazily Loading Views" href="lazyloading.html" />
|
||||
<link rel="prev" title="Message Flashing" href="flashing.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,189 +28,227 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="caching.html" title="Caching"
|
||||
<a href="lazyloading.html" title="Lazily Loading Views"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sqlalchemy.html" title="SQLAlchemy in Flask"
|
||||
<a href="flashing.html" title="Message Flashing"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Uploading Files</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="uploading-files">
|
||||
<h1>Uploading Files<a class="headerlink" href="#uploading-files" title="Link to this heading">¶</a></h1>
|
||||
<p>Ah yes, the good old problem of file uploads. The basic idea of file
|
||||
uploads is actually quite simple. It basically works like this:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre"><form></span></code> tag is marked with <code class="docutils literal notranslate"><span class="pre">enctype=multipart/form-data</span></code>
|
||||
and an <code class="docutils literal notranslate"><span class="pre"><input</span> <span class="pre">type=file></span></code> is placed in that form.</p></li>
|
||||
<li><p>The application accesses the file from the <code class="xref py py-attr docutils literal notranslate"><span class="pre">files</span></code>
|
||||
dictionary on the request object.</p></li>
|
||||
<li><p>use the <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/datastructures/#werkzeug.datastructures.FileStorage.save" title="(in Werkzeug v3.1.x)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">save()</span></code></a> method of the file to save
|
||||
the file permanently somewhere on the filesystem.</p></li>
|
||||
</ol>
|
||||
<section id="a-gentle-introduction">
|
||||
<h2>A Gentle Introduction<a class="headerlink" href="#a-gentle-introduction" title="Link to this heading">¶</a></h2>
|
||||
<p>Let’s start with a very basic application that uploads a file to a
|
||||
specific upload folder and displays a file to the user. Let’s look at the
|
||||
bootstrapping code for our application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</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="p">,</span> <span class="n">flash</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</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">secure_filename</span>
|
||||
|
||||
<span class="n">UPLOAD_FOLDER</span> <span class="o">=</span> <span class="s1">'/path/to/the/uploads'</span>
|
||||
<span class="n">ALLOWED_EXTENSIONS</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'txt'</span><span class="p">,</span> <span class="s1">'pdf'</span><span class="p">,</span> <span class="s1">'png'</span><span class="p">,</span> <span class="s1">'jpg'</span><span class="p">,</span> <span class="s1">'jpeg'</span><span class="p">,</span> <span class="s1">'gif'</span><span class="p">}</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">config</span><span class="p">[</span><span class="s1">'UPLOAD_FOLDER'</span><span class="p">]</span> <span class="o">=</span> <span class="n">UPLOAD_FOLDER</span>
|
||||
<section id="javascript-fetch-and-json">
|
||||
<h1>JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON<a class="headerlink" href="#javascript-fetch-and-json" title="Link to this heading">¶</a></h1>
|
||||
<p>You may want to make your HTML page dynamic, by changing data without
|
||||
reloading the entire page. Instead of submitting an HTML <code class="docutils literal notranslate"><span class="pre"><form></span></code> and
|
||||
performing a redirect to re-render the template, you can add
|
||||
<a class="reference external" href="https://developer.mozilla.org/Web/JavaScript">JavaScript</a> that calls <a class="reference external" href="https://developer.mozilla.org/Web/API/Fetch_API"><code class="docutils literal notranslate"><span class="pre">fetch()</span></code></a> and replaces content on the page.</p>
|
||||
<p><a class="reference external" href="https://developer.mozilla.org/Web/API/Fetch_API"><code class="docutils literal notranslate"><span class="pre">fetch()</span></code></a> is the modern, built-in JavaScript solution to making
|
||||
requests from a page. You may have heard of other “AJAX” methods and
|
||||
libraries, such as <a class="reference external" href="https://developer.mozilla.org/Web/API/XMLHttpRequest"><code class="docutils literal notranslate"><span class="pre">XMLHttpRequest()</span></code></a> or <a class="reference external" href="https://jquery.com/">jQuery</a>. These are no longer needed in
|
||||
modern browsers, although you may choose to use them or another library
|
||||
depending on your application’s requirements. These docs will only focus
|
||||
on built-in JavaScript features.</p>
|
||||
<section id="rendering-templates">
|
||||
<h2>Rendering Templates<a class="headerlink" href="#rendering-templates" title="Link to this heading">¶</a></h2>
|
||||
<p>It is important to understand the difference between templates and
|
||||
JavaScript. Templates are rendered on the server, before the response is
|
||||
sent to the user’s browser. JavaScript runs in the user’s browser, after
|
||||
the template is rendered and sent. Therefore, it is impossible to use
|
||||
JavaScript to affect how the Jinja template is rendered, but it is
|
||||
possible to render data into the JavaScript that will run.</p>
|
||||
<p>To provide data to JavaScript when rendering the template, use the
|
||||
<a class="reference external" href="https://jinja.palletsprojects.com/en/stable/templates/#jinja-filters.tojson" title="(in Jinja v3.1.x)"><code class="xref py py-func docutils literal notranslate"><span class="pre">tojson()</span></code></a> filter in a <code class="docutils literal notranslate"><span class="pre"><script></span></code> block. This will
|
||||
convert the data to a valid JavaScript object, and ensure that any
|
||||
unsafe HTML characters are rendered safely. If you do not use the
|
||||
<code class="docutils literal notranslate"><span class="pre">tojson</span></code> filter, you will get a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> in the browser
|
||||
console.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="n">generate_report</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s2">"report.html"</span><span class="p">,</span> <span class="n">chart_data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So first we need a couple of imports. Most should be straightforward, the
|
||||
<code class="xref py py-func docutils literal notranslate"><span class="pre">werkzeug.secure_filename()</span></code> is explained a little bit later. The
|
||||
<code class="docutils literal notranslate"><span class="pre">UPLOAD_FOLDER</span></code> is where we will store the uploaded files and the
|
||||
<code class="docutils literal notranslate"><span class="pre">ALLOWED_EXTENSIONS</span></code> is the set of allowed file extensions.</p>
|
||||
<p>Why do we limit the extensions that are allowed? You probably don’t want
|
||||
your users to be able to upload everything there if the server is directly
|
||||
sending out the data to the client. That way you can make sure that users
|
||||
are not able to upload HTML files that would cause XSS problems (see
|
||||
<a class="reference internal" href="../web-security.html#security-xss"><span class="std std-ref">Cross-Site Scripting (XSS)</span></a>). Also make sure to disallow <code class="docutils literal notranslate"><span class="pre">.php</span></code> files if the server
|
||||
executes them, but who has PHP installed on their server, right? :)</p>
|
||||
<p>Next the functions that check if an extension is valid and that uploads
|
||||
the file and redirects the user to the URL for the uploaded file:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">allowed_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="s1">'.'</span> <span class="ow">in</span> <span class="n">filename</span> <span class="ow">and</span> \
|
||||
<span class="n">filename</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s1">'.'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="n">ALLOWED_EXTENSIONS</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="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">upload_file</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span>
|
||||
<span class="c1"># check if the post request has the file part</span>
|
||||
<span class="k">if</span> <span class="s1">'file'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span><span class="p">:</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'No file part'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
|
||||
<span class="n">file</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span>
|
||||
<span class="c1"># If the user does not select a file, the browser submits an</span>
|
||||
<span class="c1"># empty file without a filename.</span>
|
||||
<span class="k">if</span> <span class="n">file</span><span class="o">.</span><span class="n">filename</span> <span class="o">==</span> <span class="s1">''</span><span class="p">:</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'No selected file'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">file</span> <span class="ow">and</span> <span class="n">allowed_file</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">filename</span><span class="p">):</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">secure_filename</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span>
|
||||
<span class="n">file</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'UPLOAD_FOLDER'</span><span class="p">],</span> <span class="n">filename</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'download_file'</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">filename</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="s1">'''</span>
|
||||
<span class="s1"> <!doctype html></span>
|
||||
<span class="s1"> <title>Upload new File</title></span>
|
||||
<span class="s1"> <h1>Upload new File</h1></span>
|
||||
<span class="s1"> <form method=post enctype=multipart/form-data></span>
|
||||
<span class="s1"> <input type=file name=file></span>
|
||||
<span class="s1"> <input type=submit value=Upload></span>
|
||||
<span class="s1"> </form></span>
|
||||
<span class="s1"> '''</span>
|
||||
<div class="highlight-jinja notranslate"><div class="highlight"><pre><span></span><span class="x"><script></span>
|
||||
<span class="x"> const chart_data = </span><span class="cp">{{</span> <span class="nv">chart_data</span><span class="o">|</span><span class="nf">tojson</span> <span class="cp">}}</span>
|
||||
<span class="x"> chartLib.makeChart(chart_data)</span>
|
||||
<span class="x"></script></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So what does that <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/utils/#werkzeug.utils.secure_filename" title="(in Werkzeug v3.1.x)"><code class="xref py py-func docutils literal notranslate"><span class="pre">secure_filename()</span></code></a> function actually do?
|
||||
Now the problem is that there is that principle called “never trust user
|
||||
input”. This is also true for the filename of an uploaded file. All
|
||||
submitted form data can be forged, and filenames can be dangerous. For
|
||||
the moment just remember: always use that function to secure a filename
|
||||
before storing it directly on the filesystem.</p>
|
||||
<div class="admonition-information-for-the-pros admonition">
|
||||
<p class="admonition-title">Information for the Pros</p>
|
||||
<p>So you’re interested in what that <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/utils/#werkzeug.utils.secure_filename" title="(in Werkzeug v3.1.x)"><code class="xref py py-func docutils literal notranslate"><span class="pre">secure_filename()</span></code></a>
|
||||
function does and what the problem is if you’re not using it? So just
|
||||
imagine someone would send the following information as <code class="code docutils literal notranslate"><span class="pre">filename</span></code> to
|
||||
your application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">filename</span> <span class="o">=</span> <span class="s2">"../../../../home/username/.bashrc"</span>
|
||||
<p>A less common pattern is to add the data to a <code class="docutils literal notranslate"><span class="pre">data-</span></code> attribute on an
|
||||
HTML tag. In this case, you must use single quotes around the value, not
|
||||
double quotes, otherwise you will produce invalid or unsafe HTML.</p>
|
||||
<div class="highlight-jinja notranslate"><div class="highlight"><pre><span></span><span class="x"><div data-chart='</span><span class="cp">{{</span> <span class="nv">chart_data</span><span class="o">|</span><span class="nf">tojson</span> <span class="cp">}}</span><span class="x">'></div></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Assuming the number of <code class="docutils literal notranslate"><span class="pre">../</span></code> is correct and you would join this with
|
||||
the <code class="docutils literal notranslate"><span class="pre">UPLOAD_FOLDER</span></code> the user might have the ability to modify a file on
|
||||
the server’s filesystem he or she should not modify. This does require some
|
||||
knowledge about how the application looks like, but trust me, hackers
|
||||
are patient :)</p>
|
||||
<p>Now let’s look how that function works:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">secure_filename</span><span class="p">(</span><span class="s1">'../../../../home/username/.bashrc'</span><span class="p">)</span>
|
||||
<span class="go">'home_username_.bashrc'</span>
|
||||
</section>
|
||||
<section id="generating-urls">
|
||||
<h2>Generating URLs<a class="headerlink" href="#generating-urls" title="Link to this heading">¶</a></h2>
|
||||
<p>The other way to get data from the server to JavaScript is to make a
|
||||
request for it. First, you need to know the URL to request.</p>
|
||||
<p>The simplest way to generate URLs is to continue to use
|
||||
<a class="reference internal" href="../api.html#flask.url_for" title="flask.url_for"><code class="xref py py-func docutils literal notranslate"><span class="pre">url_for()</span></code></a> when rendering the template. For example:</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">user_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">url_for</span><span class="p">(</span><span class="s2">"user"</span><span class="p">,</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="nx">current_user</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">user_url</span><span class="p">).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>We want to be able to serve the uploaded files so they can be downloaded
|
||||
by users. We’ll define a <code class="docutils literal notranslate"><span class="pre">download_file</span></code> view to serve files in the
|
||||
upload folder by name. <code class="docutils literal notranslate"><span class="pre">url_for("download_file",</span> <span class="pre">name=name)</span></code> generates
|
||||
download URLs.</p>
|
||||
<div class="highlight-python 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">send_from_directory</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/uploads/<name>'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">download_file</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">send_from_directory</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s2">"UPLOAD_FOLDER"</span><span class="p">],</span> <span class="n">name</span><span class="p">)</span>
|
||||
<p>However, you might need to generate a URL based on information you only
|
||||
know in JavaScript. As discussed above, JavaScript runs in the user’s
|
||||
browser, not as part of the template rendering, so you can’t use
|
||||
<code class="docutils literal notranslate"><span class="pre">url_for</span></code> at that point.</p>
|
||||
<p>In this case, you need to know the “root URL” under which your
|
||||
application is served. In simple setups, this is <code class="docutils literal notranslate"><span class="pre">/</span></code>, but it might
|
||||
also be something else, like <code class="docutils literal notranslate"><span class="pre">https://example.com/myapp/</span></code>.</p>
|
||||
<p>A simple way to tell your JavaScript code about this root is to set it
|
||||
as a global variable when rendering the template. Then you can use it
|
||||
when generating URLs from JavaScript.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">SCRIPT_ROOT</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">request</span><span class="p">.</span><span class="nx">script_root</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="kd">let</span><span class="w"> </span><span class="nx">user_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="c1">// do something to get a user id from the page</span>
|
||||
<span class="kd">let</span><span class="w"> </span><span class="nx">user_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">`</span><span class="si">${</span><span class="nx">SCRIPT_ROOT</span><span class="si">}</span><span class="sb">/user/</span><span class="si">${</span><span class="nx">user_id</span><span class="si">}</span><span class="sb">`</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">user_url</span><span class="p">).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you’re using middleware or the HTTP server to serve files, you can
|
||||
register the <code class="docutils literal notranslate"><span class="pre">download_file</span></code> endpoint as <code class="docutils literal notranslate"><span class="pre">build_only</span></code> so <code class="docutils literal notranslate"><span class="pre">url_for</span></code>
|
||||
will work without a view function.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span>
|
||||
<span class="s2">"/uploads/<name>"</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="s2">"download_file"</span><span class="p">,</span> <span class="n">build_only</span><span class="o">=</span><span class="kc">True</span>
|
||||
</section>
|
||||
<section id="making-a-request-with-fetch">
|
||||
<h2>Making a Request with <code class="docutils literal notranslate"><span class="pre">fetch</span></code><a class="headerlink" href="#making-a-request-with-fetch" title="Link to this heading">¶</a></h2>
|
||||
<p><a class="reference external" href="https://developer.mozilla.org/Web/API/Fetch_API"><code class="docutils literal notranslate"><span class="pre">fetch()</span></code></a> takes two arguments, a URL and an object with other options,
|
||||
and returns a <a class="reference external" href="https://developer.mozilla.org/Web/JavaScript/Reference/Global_Objects/Promise"><code class="docutils literal notranslate"><span class="pre">Promise</span></code></a>. We won’t cover all the available options, and
|
||||
will only use <code class="docutils literal notranslate"><span class="pre">then()</span></code> on the promise, not other callbacks or
|
||||
<code class="docutils literal notranslate"><span class="pre">await</span></code> syntax. Read the linked MDN docs for more information about
|
||||
those features.</p>
|
||||
<p>By default, the GET method is used. If the response contains JSON, it
|
||||
can be used with a <code class="docutils literal notranslate"><span class="pre">then()</span></code> callback chain.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">room_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">url_for</span><span class="p">(</span><span class="s2">"room_detail"</span><span class="p">,</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="nx">room</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">room_url</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// data is a parsed JSON object</span>
|
||||
<span class="w"> </span><span class="p">})</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To send data, use a data method such as POST, and pass the <code class="docutils literal notranslate"><span class="pre">body</span></code>
|
||||
option. The most common types for data are form data or JSON data.</p>
|
||||
<p>To send form data, pass a populated <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/API/FormData"><code class="docutils literal notranslate"><span class="pre">FormData</span></code></a> object. This uses the
|
||||
same format as an HTML form, and would be accessed with <code class="docutils literal notranslate"><span class="pre">request.form</span></code>
|
||||
in a Flask view.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">let</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">FormData</span><span class="p">()</span>
|
||||
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">"name"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Flask Room"</span><span class="p">)</span>
|
||||
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">"description"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Talk about Flask here."</span><span class="p">)</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">room_url</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="s2">"method"</span><span class="o">:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"body"</span><span class="o">:</span><span class="w"> </span><span class="nx">data</span><span class="p">,</span>
|
||||
<span class="p">}).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In general, prefer sending request data as form data, as would be used
|
||||
when submitting an HTML form. JSON can represent more complex data, but
|
||||
unless you need that it’s better to stick with the simpler format. When
|
||||
sending JSON data, the <code class="docutils literal notranslate"><span class="pre">Content-Type:</span> <span class="pre">application/json</span></code> header must be
|
||||
sent as well, otherwise Flask will return a 400 error.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">let</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="s2">"name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Flask Room"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"description"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Talk about Flask here."</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">room_url</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="s2">"method"</span><span class="o">:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"headers"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="s2">"Content-Type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"application/json"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="s2">"body"</span><span class="o">:</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">),</span>
|
||||
<span class="p">}).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="following-redirects">
|
||||
<h2>Following Redirects<a class="headerlink" href="#following-redirects" title="Link to this heading">¶</a></h2>
|
||||
<p>A response might be a redirect, for example if you logged in with
|
||||
JavaScript instead of a traditional HTML form, and your view returned
|
||||
a redirect instead of JSON. JavaScript requests do follow redirects, but
|
||||
they don’t change the page. If you want to make the page change you can
|
||||
inspect the response and apply the redirect manually.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="nx">fetch</span><span class="p">(</span><span class="s2">"/login"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="s2">"body"</span><span class="o">:</span><span class="w"> </span><span class="p">...}).</span><span class="nx">then</span><span class="p">(</span>
|
||||
<span class="w"> </span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">redirected</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">url</span>
|
||||
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nx">showLoginError</span><span class="p">()</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="improving-uploads">
|
||||
<h2>Improving Uploads<a class="headerlink" href="#improving-uploads" title="Link to this heading">¶</a></h2>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.6.</span></p>
|
||||
</div>
|
||||
</details><p>So how exactly does Flask handle uploads? Well it will store them in the
|
||||
webserver’s memory if the files are reasonably small, otherwise in a
|
||||
temporary location (as returned by <a class="reference external" href="https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">tempfile.gettempdir()</span></code></a>). But how
|
||||
do you specify the maximum file size after which an upload is aborted? By
|
||||
default Flask will happily accept file uploads with an unlimited amount of
|
||||
memory, but you can limit that by setting the <code class="docutils literal notranslate"><span class="pre">MAX_CONTENT_LENGTH</span></code>
|
||||
config key:</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="p">,</span> <span class="n">Request</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">config</span><span class="p">[</span><span class="s1">'MAX_CONTENT_LENGTH'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">16</span> <span class="o">*</span> <span class="mi">1000</span> <span class="o">*</span> <span class="mi">1000</span>
|
||||
<section id="replacing-content">
|
||||
<h2>Replacing Content<a class="headerlink" href="#replacing-content" title="Link to this heading">¶</a></h2>
|
||||
<p>A response might be new HTML, either a new section of the page to add or
|
||||
replace, or an entirely new page. In general, if you’re returning the
|
||||
entire page, it would be better to handle that with a redirect as shown
|
||||
in the previous section. The following example shows how to replace a
|
||||
<code class="docutils literal notranslate"><span class="pre"><div></span></code> with the HTML returned by a request.</p>
|
||||
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"geology-fact"</span><span class="p">></span>
|
||||
{{ include "geology_fact.html" }}
|
||||
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">script</span><span class="p">></span>
|
||||
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">geology_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">url_for</span><span class="p">(</span><span class="s2">"geology_fact"</span><span class="p">)</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">geology_div</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"geology-fact"</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="nx">fetch</span><span class="p">(</span><span class="nx">geology_url</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">text</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">text</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">geology_div</span><span class="p">.</span><span class="nx">innerHTML</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">text</span><span class="p">)</span>
|
||||
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The code above will limit the maximum allowed payload to 16 megabytes.
|
||||
If a larger file is transmitted, Flask will raise a
|
||||
<a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/exceptions/#werkzeug.exceptions.RequestEntityTooLarge" title="(in Werkzeug v3.1.x)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">RequestEntityTooLarge</span></code></a> exception.</p>
|
||||
<div class="admonition-connection-reset-issue admonition">
|
||||
<p class="admonition-title">Connection Reset Issue</p>
|
||||
<p>When using the local development server, you may get a connection
|
||||
reset error instead of a 413 response. You will get the correct
|
||||
status response when running the app with a production WSGI server.</p>
|
||||
</section>
|
||||
<section id="return-json-from-views">
|
||||
<h2>Return JSON from Views<a class="headerlink" href="#return-json-from-views" title="Link to this heading">¶</a></h2>
|
||||
<p>To return a JSON object from your API view, you can directly return a
|
||||
dict from the view. It will be serialized to JSON automatically.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/user/<int:id>"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">user_detail</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">get_or_404</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">{</span>
|
||||
<span class="s2">"username"</span><span class="p">:</span> <span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="p">,</span>
|
||||
<span class="s2">"email"</span><span class="p">:</span> <span class="n">User</span><span class="o">.</span><span class="n">email</span><span class="p">,</span>
|
||||
<span class="s2">"picture"</span><span class="p">:</span> <span class="n">url_for</span><span class="p">(</span><span class="s2">"static"</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="sa">f</span><span class="s2">"users/</span><span class="si">{</span><span class="nb">id</span><span class="si">}</span><span class="s2">/profile.png"</span><span class="p">),</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This feature was added in Flask 0.6 but can be achieved in older versions
|
||||
as well by subclassing the request object. For more information on that
|
||||
consult the Werkzeug documentation on file handling.</p>
|
||||
<p>If you want to return another JSON type, use the
|
||||
<a class="reference internal" href="../api.html#flask.json.jsonify" title="flask.json.jsonify"><code class="xref py py-func docutils literal notranslate"><span class="pre">jsonify()</span></code></a> function, which creates a response object
|
||||
with the given data serialized to JSON.</p>
|
||||
<div class="highlight-python 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">jsonify</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/users"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">user_list</span><span class="p">():</span>
|
||||
<span class="n">users</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">name</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">jsonify</span><span class="p">([</span><span class="n">u</span><span class="o">.</span><span class="n">to_json</span><span class="p">()</span> <span class="k">for</span> <span class="n">u</span> <span class="ow">in</span> <span class="n">users</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It is usually not a good idea to return file data in a JSON response.
|
||||
JSON cannot represent binary data directly, so it must be base64
|
||||
encoded, which can be slow, takes more bandwidth to send, and is not as
|
||||
easy to cache. Instead, serve files using one view, and generate a URL
|
||||
to the desired file to include in the JSON. Then the client can make a
|
||||
separate request to get the linked resource after getting the JSON.</p>
|
||||
</section>
|
||||
<section id="upload-progress-bars">
|
||||
<h2>Upload Progress Bars<a class="headerlink" href="#upload-progress-bars" title="Link to this heading">¶</a></h2>
|
||||
<p>A while ago many developers had the idea to read the incoming file in
|
||||
small chunks and store the upload progress in the database to be able to
|
||||
poll the progress with JavaScript from the client. The client asks the
|
||||
server every 5 seconds how much it has transmitted, but this is
|
||||
something it should already know.</p>
|
||||
</section>
|
||||
<section id="an-easier-solution">
|
||||
<h2>An Easier Solution<a class="headerlink" href="#an-easier-solution" title="Link to this heading">¶</a></h2>
|
||||
<p>Now there are better solutions that work faster and are more reliable. There
|
||||
are JavaScript libraries like <a class="reference external" href="https://jquery.com/">jQuery</a> that have form plugins to ease the
|
||||
construction of progress bar.</p>
|
||||
<p>Because the common pattern for file uploads exists almost unchanged in all
|
||||
applications dealing with uploads, there are also some Flask extensions that
|
||||
implement a full fledged upload mechanism that allows controlling which
|
||||
file extensions are allowed to be uploaded.</p>
|
||||
<section id="receiving-json-in-views">
|
||||
<h2>Receiving JSON in Views<a class="headerlink" href="#receiving-json-in-views" title="Link to this heading">¶</a></h2>
|
||||
<p>Use the <a class="reference internal" href="../api.html#flask.Request.json" title="flask.Request.json"><code class="xref py py-attr docutils literal notranslate"><span class="pre">json</span></code></a> property of the
|
||||
<a class="reference internal" href="../api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> object to decode the request’s body as JSON. If
|
||||
the body is not valid JSON, or the <code class="docutils literal notranslate"><span class="pre">Content-Type</span></code> header is not set to
|
||||
<code class="docutils literal notranslate"><span class="pre">application/json</span></code>, a 400 Bad Request error will be raised.</p>
|
||||
<div class="highlight-python 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">request</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/user/<int:id>"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">user_update</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">get_or_404</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
|
||||
<span class="n">user</span><span class="o">.</span><span class="n">update_from_json</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">json</span><span class="p">)</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">user</span><span class="o">.</span><span class="n">to_json</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -222,20 +260,23 @@ file extensions are allowed to be uploaded.</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="#">Uploading Files</a><ul>
|
||||
<li><a class="reference internal" href="#a-gentle-introduction">A Gentle Introduction</a></li>
|
||||
<li><a class="reference internal" href="#improving-uploads">Improving Uploads</a></li>
|
||||
<li><a class="reference internal" href="#upload-progress-bars">Upload Progress Bars</a></li>
|
||||
<li><a class="reference internal" href="#an-easier-solution">An Easier Solution</a></li>
|
||||
<li><a class="reference internal" href="#">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a><ul>
|
||||
<li><a class="reference internal" href="#rendering-templates">Rendering Templates</a></li>
|
||||
<li><a class="reference internal" href="#generating-urls">Generating URLs</a></li>
|
||||
<li><a class="reference internal" href="#making-a-request-with-fetch">Making a Request with <code class="docutils literal notranslate"><span class="pre">fetch</span></code></a></li>
|
||||
<li><a class="reference internal" href="#following-redirects">Following Redirects</a></li>
|
||||
<li><a class="reference internal" href="#replacing-content">Replacing Content</a></li>
|
||||
<li><a class="reference internal" href="#return-json-from-views">Return JSON from Views</a></li>
|
||||
<li><a class="reference internal" href="#receiving-json-in-views">Receiving JSON in Views</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -245,8 +286,8 @@ file extensions are allowed to be uploaded.</p>
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="sqlalchemy.html" title="previous chapter">SQLAlchemy in Flask</a>
|
||||
<li>Next: <a href="caching.html" title="next chapter">Caching</a></ul>
|
||||
<li>Previous: <a href="flashing.html" title="previous chapter">Message Flashing</a>
|
||||
<li>Next: <a href="lazyloading.html" title="next chapter">Lazily Loading Views</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -270,4 +311,4 @@ file extensions are allowed to be uploaded.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Message Flashing — Flask Documentation (3.2.x)</title>
|
||||
<title>AJAX with jQuery — 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,6 @@
|
|||
<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="JavaScript, fetch, and JSON" href="javascript.html" />
|
||||
<link rel="prev" title="Template Inheritance" href="templateinheritance.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -27,162 +25,19 @@
|
|||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="javascript.html" title="JavaScript, fetch, and JSON"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="templateinheritance.html" title="Template Inheritance"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Message Flashing</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">AJAX with jQuery</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="message-flashing">
|
||||
<h1>Message Flashing<a class="headerlink" href="#message-flashing" title="Link to this heading">¶</a></h1>
|
||||
<p>Good applications and user interfaces are all about feedback. If the user
|
||||
does not get enough feedback they will probably end up hating the
|
||||
application. Flask provides a really simple way to give feedback to a
|
||||
user with the flashing system. The flashing system basically makes it
|
||||
possible to record a message at the end of a request and access it next
|
||||
request and only next request. This is usually combined with a layout
|
||||
template that does this. Note that browsers and sometimes web servers enforce
|
||||
a limit on cookie sizes. This means that flashing messages that are too
|
||||
large for session cookies causes message flashing to fail silently.</p>
|
||||
<section id="simple-flashing">
|
||||
<h2>Simple Flashing<a class="headerlink" href="#simple-flashing" title="Link to this heading">¶</a></h2>
|
||||
<p>So here is a full example:</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="p">,</span> <span class="n">flash</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">render_template</span><span class="p">,</span> \
|
||||
<span class="n">request</span><span class="p">,</span> <span class="n">url_for</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">secret_key</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">'_5#y2L"F4Q8z</span><span class="se">\n\xec</span><span class="s1">]/'</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="n">render_template</span><span class="p">(</span><span class="s1">'index.html'</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">'/login'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">login</span><span class="p">():</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">'username'</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">'admin'</span> <span class="ow">or</span> \
|
||||
<span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">'password'</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">'secret'</span><span class="p">:</span>
|
||||
<span class="n">error</span> <span class="o">=</span> <span class="s1">'Invalid credentials'</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'You were successfully logged in'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'index'</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">'login.html'</span><span class="p">,</span> <span class="n">error</span><span class="o">=</span><span class="n">error</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And here is the <code class="file docutils literal notranslate"><span class="pre">layout.html</span></code> template which does the magic:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp"><!doctype html></span>
|
||||
<span class="p"><</span><span class="nt">title</span><span class="p">></span>My Application<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">with</span> <span class="nv">messages</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">()</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">flashes</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">message</span> <span class="k">in</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">message</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here is the <code class="file docutils literal notranslate"><span class="pre">index.html</span></code> template which inherits from <code class="file docutils literal notranslate"><span class="pre">layout.html</span></code>:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Overview<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Do you want to <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'login'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>log in?<span class="p"></</span><span class="nt">a</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And here is the <code class="file docutils literal notranslate"><span class="pre">login.html</span></code> template which also inherits from
|
||||
<code class="file docutils literal notranslate"><span class="pre">layout.html</span></code>:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Login<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">error</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">error</span><span class="p">><</span><span class="nt">strong</span><span class="p">></span>Error:<span class="p"></</span><span class="nt">strong</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">error</span> <span class="cp">}}</span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">post</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dt</span><span class="p">></span>Username:
|
||||
<span class="p"><</span><span class="nt">dd</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">text</span> <span class="na">name</span><span class="o">=</span><span class="s">username</span> <span class="na">value</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span>
|
||||
<span class="nv">request.form.username</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dt</span><span class="p">></span>Password:
|
||||
<span class="p"><</span><span class="nt">dd</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">password</span> <span class="na">name</span><span class="o">=</span><span class="s">password</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">submit</span> <span class="na">value</span><span class="o">=</span><span class="s">Login</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="flashing-with-categories">
|
||||
<h2>Flashing With Categories<a class="headerlink" href="#flashing-with-categories" title="Link to this heading">¶</a></h2>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.3.</span></p>
|
||||
</div>
|
||||
</details><p>It is also possible to provide categories when flashing a message. The
|
||||
default category if nothing is provided is <code class="docutils literal notranslate"><span class="pre">'message'</span></code>. Alternative
|
||||
categories can be used to give the user better feedback. For example
|
||||
error messages could be displayed with a red background.</p>
|
||||
<p>To flash a message with a different category, just use the second argument
|
||||
to the <a class="reference internal" href="../api.html#flask.flash" title="flask.flash"><code class="xref py py-func docutils literal notranslate"><span class="pre">flash()</span></code></a> function:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">flash</span><span class="p">(</span><span class="s1">'Invalid password provided'</span><span class="p">,</span> <span class="s1">'error'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Inside the template you then have to tell the
|
||||
<a class="reference internal" href="../api.html#flask.get_flashed_messages" title="flask.get_flashed_messages"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_flashed_messages()</span></code></a> function to also return the
|
||||
categories. The loop looks slightly different in that situation then:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">with</span> <span class="nv">messages</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">(</span><span class="nv">with_categories</span><span class="o">=</span><span class="kp">true</span><span class="o">)</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">flashes</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">category</span><span class="o">,</span> <span class="nv">message</span> <span class="k">in</span> <span class="nv">messages</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">category</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">message</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is just one example of how to render these flashed messages. One
|
||||
might also use the category to add a prefix such as
|
||||
<code class="docutils literal notranslate"><span class="pre"><strong>Error:</strong></span></code> to the message.</p>
|
||||
</section>
|
||||
<section id="filtering-flash-messages">
|
||||
<h2>Filtering Flash Messages<a class="headerlink" href="#filtering-flash-messages" title="Link to this heading">¶</a></h2>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.9.</span></p>
|
||||
</div>
|
||||
</details><p>Optionally you can pass a list of categories which filters the results of
|
||||
<a class="reference internal" href="../api.html#flask.get_flashed_messages" title="flask.get_flashed_messages"><code class="xref py py-func docutils literal notranslate"><span class="pre">get_flashed_messages()</span></code></a>. This is useful if you wish to
|
||||
render each category in a separate block.</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">with</span> <span class="nv">errors</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">(</span><span class="nv">category_filter</span><span class="o">=[</span><span class="s2">"error"</span><span class="o">])</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"alert-message block-message error"</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">"close"</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span>×<span class="p"></</span><span class="nt">a</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span>- <span class="k">for</span> <span class="nv">msg</span> <span class="k">in</span> <span class="nv">errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">msg</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> -<span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="ajax-with-jquery">
|
||||
<h1>AJAX with jQuery<a class="headerlink" href="#ajax-with-jquery" title="Link to this heading">¶</a></h1>
|
||||
<p>Obsolete, see <a class="reference internal" href="javascript.html"><span class="doc">JavaScript, fetch, and JSON</span></a> instead.</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -193,32 +48,16 @@ render each category in a separate block.</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="#">Message Flashing</a><ul>
|
||||
<li><a class="reference internal" href="#simple-flashing">Simple Flashing</a></li>
|
||||
<li><a class="reference internal" href="#flashing-with-categories">Flashing With Categories</a></li>
|
||||
<li><a class="reference internal" href="#filtering-flash-messages">Filtering Flash Messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="templateinheritance.html" title="previous chapter">Template Inheritance</a>
|
||||
<li>Next: <a href="javascript.html" title="next chapter">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<search id="searchbox" style="display: none" role="search">
|
||||
|
|
@ -240,4 +79,4 @@ render each category in a separate block.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Patterns for Flask — Flask Documentation (3.2.x)</title>
|
||||
<title>Lazily Loading Views — 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="Large Applications as Packages" href="packages.html" />
|
||||
<link rel="prev" title="Working with the Shell" href="../shell.html" />
|
||||
<link rel="next" title="MongoDB with MongoEngine" href="mongoengine.html" />
|
||||
<link rel="prev" title="JavaScript, fetch, and JSON" href="javascript.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,153 +28,126 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="packages.html" title="Large Applications as Packages"
|
||||
<a href="mongoengine.html" title="MongoDB with MongoEngine"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../shell.html" title="Working with the Shell"
|
||||
<a href="javascript.html" title="JavaScript, fetch, and JSON"
|
||||
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="">Patterns for Flask</a></li>
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Lazily Loading Views</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="patterns-for-flask">
|
||||
<h1>Patterns for Flask<a class="headerlink" href="#patterns-for-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>Certain features and interactions are common enough that you will find
|
||||
them in most web applications. For example, many applications use a
|
||||
relational database and user authentication. They will open a database
|
||||
connection at the beginning of the request and get the information for
|
||||
the logged in user. At the end of the request, the database connection
|
||||
is closed.</p>
|
||||
<p>These types of patterns may be a bit outside the scope of Flask itself,
|
||||
but Flask makes it easy to implement them. Some common patterns are
|
||||
collected in the following pages.</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="packages.html">Large Applications as Packages</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="packages.html#simple-packages">Simple Packages</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="packages.html#working-with-blueprints">Working with Blueprints</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="appfactories.html">Application Factories</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#basic-factories">Basic Factories</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#factories-extensions">Factories & Extensions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#using-applications">Using Applications</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appfactories.html#factory-improvements">Factory Improvements</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="appdispatch.html">Application Dispatching</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#working-with-this-document">Working with this Document</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#combining-applications">Combining Applications</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#dispatch-by-subdomain">Dispatch by Subdomain</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#dispatch-by-path">Dispatch by Path</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="urlprocessors.html">Using URL Processors</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="urlprocessors.html#internationalized-application-urls">Internationalized Application URLs</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="urlprocessors.html#internationalized-blueprint-urls">Internationalized Blueprint URLs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="sqlite3.html">Using SQLite 3 with Flask</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#connect-on-demand">Connect on Demand</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#easy-querying">Easy Querying</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#initial-schemas">Initial Schemas</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="sqlalchemy.html">SQLAlchemy in Flask</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#flask-sqlalchemy-extension">Flask-SQLAlchemy Extension</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#declarative">Declarative</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#manual-object-relational-mapping">Manual Object Relational Mapping</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#sql-abstraction-layer">SQL Abstraction Layer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="fileuploads.html">Uploading Files</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#a-gentle-introduction">A Gentle Introduction</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#improving-uploads">Improving Uploads</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#upload-progress-bars">Upload Progress Bars</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#an-easier-solution">An Easier Solution</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="caching.html">Caching</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="viewdecorators.html">View Decorators</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#login-required-decorator">Login Required Decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#caching-decorator">Caching Decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#templating-decorator">Templating Decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#endpoint-decorator">Endpoint Decorator</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="wtforms.html">Form Validation with WTForms</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="wtforms.html#the-forms">The Forms</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="wtforms.html#in-the-view">In the View</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="wtforms.html#forms-in-templates">Forms in Templates</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="templateinheritance.html">Template Inheritance</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="templateinheritance.html#base-template">Base Template</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="templateinheritance.html#child-template">Child Template</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="flashing.html">Message Flashing</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="flashing.html#simple-flashing">Simple Flashing</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="flashing.html#flashing-with-categories">Flashing With Categories</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="flashing.html#filtering-flash-messages">Filtering Flash Messages</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="javascript.html">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#rendering-templates">Rendering Templates</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#generating-urls">Generating URLs</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#making-a-request-with-fetch">Making a Request with <code class="docutils literal notranslate"><span class="pre">fetch</span></code></a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#following-redirects">Following Redirects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#replacing-content">Replacing Content</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#return-json-from-views">Return JSON from Views</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="javascript.html#receiving-json-in-views">Receiving JSON in Views</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="lazyloading.html">Lazily Loading Views</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="lazyloading.html#converting-to-centralized-url-map">Converting to Centralized URL Map</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="lazyloading.html#loading-late">Loading Late</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="mongoengine.html">MongoDB with MongoEngine</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#configuration">Configuration</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#mapping-documents">Mapping Documents</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#creating-data">Creating Data</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#queries">Queries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="mongoengine.html#documentation">Documentation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="favicon.html">Adding a favicon</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="favicon.html#see-also">See also</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="streaming.html">Streaming Contents</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="streaming.html#basic-usage">Basic Usage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="streaming.html#streaming-from-templates">Streaming from Templates</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="streaming.html#streaming-with-context">Streaming with Context</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="deferredcallbacks.html">Deferred Request Callbacks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="methodoverrides.html">Adding HTTP Method Overrides</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="requestchecksum.html">Request Content Checksums</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="celery.html">Background Tasks with Celery</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#install">Install</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#integrate-celery-with-flask">Integrate Celery with Flask</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#application-factory">Application Factory</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#defining-tasks">Defining Tasks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#calling-tasks">Calling Tasks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#getting-results">Getting Results</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="celery.html#passing-data-to-tasks">Passing Data to Tasks</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="subclassing.html">Subclassing Flask</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="singlepageapplications.html">Single-Page Applications</a></li>
|
||||
</ul>
|
||||
|
||||
<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 Google’s 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>
|
||||
<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">pass</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/user/<username>'</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>
|
||||
</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>
|
||||
</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">'/'</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">'/user/<username>'</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>
|
||||
</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">'.'</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>What’s 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 don’t 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">'/'</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">'yourapplication.views.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">'/user/<username>'</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">'yourapplication.views.user'</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">"yourapplication.</span><span class="si">{</span><span class="n">import_name</span><span class="si">}</span><span class="s2">"</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">'views.index'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'/'</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">'/user/'</span><span class="p">,</span><span class="s1">'/user/<username>'</span><span class="p">]</span>
|
||||
<span class="n">url</span><span class="p">(</span><span class="s1">'views.user'</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>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -185,18 +158,30 @@ collected in the following pages.</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>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="../shell.html" title="previous chapter">Working with the Shell</a>
|
||||
<li>Next: <a href="packages.html" title="next chapter">Large Applications as Packages</a>
|
||||
<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>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -219,4 +204,4 @@ collected in the following pages.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>JavaScript, fetch, and JSON — Flask Documentation (3.2.x)</title>
|
||||
<title>Adding HTTP Method Overrides — 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="Lazily Loading Views" href="lazyloading.html" />
|
||||
<link rel="prev" title="Message Flashing" href="flashing.html" />
|
||||
<link rel="next" title="Request Content Checksums" href="requestchecksum.html" />
|
||||
<link rel="prev" title="Deferred Request Callbacks" href="deferredcallbacks.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,228 +28,62 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="lazyloading.html" title="Lazily Loading Views"
|
||||
<a href="requestchecksum.html" title="Request Content Checksums"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="flashing.html" title="Message Flashing"
|
||||
<a href="deferredcallbacks.html" title="Deferred Request Callbacks"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Adding HTTP Method Overrides</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="javascript-fetch-and-json">
|
||||
<h1>JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON<a class="headerlink" href="#javascript-fetch-and-json" title="Link to this heading">¶</a></h1>
|
||||
<p>You may want to make your HTML page dynamic, by changing data without
|
||||
reloading the entire page. Instead of submitting an HTML <code class="docutils literal notranslate"><span class="pre"><form></span></code> and
|
||||
performing a redirect to re-render the template, you can add
|
||||
<a class="reference external" href="https://developer.mozilla.org/Web/JavaScript">JavaScript</a> that calls <a class="reference external" href="https://developer.mozilla.org/Web/API/Fetch_API"><code class="docutils literal notranslate"><span class="pre">fetch()</span></code></a> and replaces content on the page.</p>
|
||||
<p><a class="reference external" href="https://developer.mozilla.org/Web/API/Fetch_API"><code class="docutils literal notranslate"><span class="pre">fetch()</span></code></a> is the modern, built-in JavaScript solution to making
|
||||
requests from a page. You may have heard of other “AJAX” methods and
|
||||
libraries, such as <a class="reference external" href="https://developer.mozilla.org/Web/API/XMLHttpRequest"><code class="docutils literal notranslate"><span class="pre">XMLHttpRequest()</span></code></a> or <a class="reference external" href="https://jquery.com/">jQuery</a>. These are no longer needed in
|
||||
modern browsers, although you may choose to use them or another library
|
||||
depending on your application’s requirements. These docs will only focus
|
||||
on built-in JavaScript features.</p>
|
||||
<section id="rendering-templates">
|
||||
<h2>Rendering Templates<a class="headerlink" href="#rendering-templates" title="Link to this heading">¶</a></h2>
|
||||
<p>It is important to understand the difference between templates and
|
||||
JavaScript. Templates are rendered on the server, before the response is
|
||||
sent to the user’s browser. JavaScript runs in the user’s browser, after
|
||||
the template is rendered and sent. Therefore, it is impossible to use
|
||||
JavaScript to affect how the Jinja template is rendered, but it is
|
||||
possible to render data into the JavaScript that will run.</p>
|
||||
<p>To provide data to JavaScript when rendering the template, use the
|
||||
<a class="reference external" href="https://jinja.palletsprojects.com/en/stable/templates/#jinja-filters.tojson" title="(in Jinja v3.1.x)"><code class="xref py py-func docutils literal notranslate"><span class="pre">tojson()</span></code></a> filter in a <code class="docutils literal notranslate"><span class="pre"><script></span></code> block. This will
|
||||
convert the data to a valid JavaScript object, and ensure that any
|
||||
unsafe HTML characters are rendered safely. If you do not use the
|
||||
<code class="docutils literal notranslate"><span class="pre">tojson</span></code> filter, you will get a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> in the browser
|
||||
console.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="n">generate_report</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s2">"report.html"</span><span class="p">,</span> <span class="n">chart_data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-jinja notranslate"><div class="highlight"><pre><span></span><span class="x"><script></span>
|
||||
<span class="x"> const chart_data = </span><span class="cp">{{</span> <span class="nv">chart_data</span><span class="o">|</span><span class="nf">tojson</span> <span class="cp">}}</span>
|
||||
<span class="x"> chartLib.makeChart(chart_data)</span>
|
||||
<span class="x"></script></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A less common pattern is to add the data to a <code class="docutils literal notranslate"><span class="pre">data-</span></code> attribute on an
|
||||
HTML tag. In this case, you must use single quotes around the value, not
|
||||
double quotes, otherwise you will produce invalid or unsafe HTML.</p>
|
||||
<div class="highlight-jinja notranslate"><div class="highlight"><pre><span></span><span class="x"><div data-chart='</span><span class="cp">{{</span> <span class="nv">chart_data</span><span class="o">|</span><span class="nf">tojson</span> <span class="cp">}}</span><span class="x">'></div></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="generating-urls">
|
||||
<h2>Generating URLs<a class="headerlink" href="#generating-urls" title="Link to this heading">¶</a></h2>
|
||||
<p>The other way to get data from the server to JavaScript is to make a
|
||||
request for it. First, you need to know the URL to request.</p>
|
||||
<p>The simplest way to generate URLs is to continue to use
|
||||
<a class="reference internal" href="../api.html#flask.url_for" title="flask.url_for"><code class="xref py py-func docutils literal notranslate"><span class="pre">url_for()</span></code></a> when rendering the template. For example:</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">user_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">url_for</span><span class="p">(</span><span class="s2">"user"</span><span class="p">,</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="nx">current_user</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">user_url</span><span class="p">).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>However, you might need to generate a URL based on information you only
|
||||
know in JavaScript. As discussed above, JavaScript runs in the user’s
|
||||
browser, not as part of the template rendering, so you can’t use
|
||||
<code class="docutils literal notranslate"><span class="pre">url_for</span></code> at that point.</p>
|
||||
<p>In this case, you need to know the “root URL” under which your
|
||||
application is served. In simple setups, this is <code class="docutils literal notranslate"><span class="pre">/</span></code>, but it might
|
||||
also be something else, like <code class="docutils literal notranslate"><span class="pre">https://example.com/myapp/</span></code>.</p>
|
||||
<p>A simple way to tell your JavaScript code about this root is to set it
|
||||
as a global variable when rendering the template. Then you can use it
|
||||
when generating URLs from JavaScript.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">SCRIPT_ROOT</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">request</span><span class="p">.</span><span class="nx">script_root</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="kd">let</span><span class="w"> </span><span class="nx">user_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="c1">// do something to get a user id from the page</span>
|
||||
<span class="kd">let</span><span class="w"> </span><span class="nx">user_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">`</span><span class="si">${</span><span class="nx">SCRIPT_ROOT</span><span class="si">}</span><span class="sb">/user/</span><span class="si">${</span><span class="nx">user_id</span><span class="si">}</span><span class="sb">`</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">user_url</span><span class="p">).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="making-a-request-with-fetch">
|
||||
<h2>Making a Request with <code class="docutils literal notranslate"><span class="pre">fetch</span></code><a class="headerlink" href="#making-a-request-with-fetch" title="Link to this heading">¶</a></h2>
|
||||
<p><a class="reference external" href="https://developer.mozilla.org/Web/API/Fetch_API"><code class="docutils literal notranslate"><span class="pre">fetch()</span></code></a> takes two arguments, a URL and an object with other options,
|
||||
and returns a <a class="reference external" href="https://developer.mozilla.org/Web/JavaScript/Reference/Global_Objects/Promise"><code class="docutils literal notranslate"><span class="pre">Promise</span></code></a>. We won’t cover all the available options, and
|
||||
will only use <code class="docutils literal notranslate"><span class="pre">then()</span></code> on the promise, not other callbacks or
|
||||
<code class="docutils literal notranslate"><span class="pre">await</span></code> syntax. Read the linked MDN docs for more information about
|
||||
those features.</p>
|
||||
<p>By default, the GET method is used. If the response contains JSON, it
|
||||
can be used with a <code class="docutils literal notranslate"><span class="pre">then()</span></code> callback chain.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span><span class="w"> </span><span class="nx">room_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">url_for</span><span class="p">(</span><span class="s2">"room_detail"</span><span class="p">,</span><span class="w"> </span><span class="nx">id</span><span class="o">=</span><span class="nx">room</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">room_url</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="c1">// data is a parsed JSON object</span>
|
||||
<span class="w"> </span><span class="p">})</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To send data, use a data method such as POST, and pass the <code class="docutils literal notranslate"><span class="pre">body</span></code>
|
||||
option. The most common types for data are form data or JSON data.</p>
|
||||
<p>To send form data, pass a populated <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/API/FormData"><code class="docutils literal notranslate"><span class="pre">FormData</span></code></a> object. This uses the
|
||||
same format as an HTML form, and would be accessed with <code class="docutils literal notranslate"><span class="pre">request.form</span></code>
|
||||
in a Flask view.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">let</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">FormData</span><span class="p">()</span>
|
||||
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">"name"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Flask Room"</span><span class="p">)</span>
|
||||
<span class="nx">data</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">"description"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Talk about Flask here."</span><span class="p">)</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">room_url</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="s2">"method"</span><span class="o">:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"body"</span><span class="o">:</span><span class="w"> </span><span class="nx">data</span><span class="p">,</span>
|
||||
<span class="p">}).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In general, prefer sending request data as form data, as would be used
|
||||
when submitting an HTML form. JSON can represent more complex data, but
|
||||
unless you need that it’s better to stick with the simpler format. When
|
||||
sending JSON data, the <code class="docutils literal notranslate"><span class="pre">Content-Type:</span> <span class="pre">application/json</span></code> header must be
|
||||
sent as well, otherwise Flask will return a 400 error.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">let</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="s2">"name"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Flask Room"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"description"</span><span class="o">:</span><span class="w"> </span><span class="s2">"Talk about Flask here."</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">fetch</span><span class="p">(</span><span class="nx">room_url</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="s2">"method"</span><span class="o">:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
|
||||
<span class="w"> </span><span class="s2">"headers"</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="s2">"Content-Type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"application/json"</span><span class="p">},</span>
|
||||
<span class="w"> </span><span class="s2">"body"</span><span class="o">:</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">),</span>
|
||||
<span class="p">}).</span><span class="nx">then</span><span class="p">(...)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="following-redirects">
|
||||
<h2>Following Redirects<a class="headerlink" href="#following-redirects" title="Link to this heading">¶</a></h2>
|
||||
<p>A response might be a redirect, for example if you logged in with
|
||||
JavaScript instead of a traditional HTML form, and your view returned
|
||||
a redirect instead of JSON. JavaScript requests do follow redirects, but
|
||||
they don’t change the page. If you want to make the page change you can
|
||||
inspect the response and apply the redirect manually.</p>
|
||||
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="nx">fetch</span><span class="p">(</span><span class="s2">"/login"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="s2">"body"</span><span class="o">:</span><span class="w"> </span><span class="p">...}).</span><span class="nx">then</span><span class="p">(</span>
|
||||
<span class="w"> </span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">redirected</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">url</span>
|
||||
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||||
<span class="w"> </span><span class="nx">showLoginError</span><span class="p">()</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p">}</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="replacing-content">
|
||||
<h2>Replacing Content<a class="headerlink" href="#replacing-content" title="Link to this heading">¶</a></h2>
|
||||
<p>A response might be new HTML, either a new section of the page to add or
|
||||
replace, or an entirely new page. In general, if you’re returning the
|
||||
entire page, it would be better to handle that with a redirect as shown
|
||||
in the previous section. The following example shows how to replace a
|
||||
<code class="docutils literal notranslate"><span class="pre"><div></span></code> with the HTML returned by a request.</p>
|
||||
<div class="highlight-html notranslate"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"geology-fact"</span><span class="p">></span>
|
||||
{{ include "geology_fact.html" }}
|
||||
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">script</span><span class="p">></span>
|
||||
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">geology_url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{{</span><span class="w"> </span><span class="nx">url_for</span><span class="p">(</span><span class="s2">"geology_fact"</span><span class="p">)</span><span class="o">|</span><span class="nx">tojson</span><span class="w"> </span><span class="p">}}</span>
|
||||
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">geology_div</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"geology-fact"</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="nx">fetch</span><span class="p">(</span><span class="nx">geology_url</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">text</span><span class="p">)</span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">text</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">geology_div</span><span class="p">.</span><span class="nx">innerHTML</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">text</span><span class="p">)</span>
|
||||
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="return-json-from-views">
|
||||
<h2>Return JSON from Views<a class="headerlink" href="#return-json-from-views" title="Link to this heading">¶</a></h2>
|
||||
<p>To return a JSON object from your API view, you can directly return a
|
||||
dict from the view. It will be serialized to JSON automatically.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/user/<int:id>"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">user_detail</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">get_or_404</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="p">{</span>
|
||||
<span class="s2">"username"</span><span class="p">:</span> <span class="n">User</span><span class="o">.</span><span class="n">username</span><span class="p">,</span>
|
||||
<span class="s2">"email"</span><span class="p">:</span> <span class="n">User</span><span class="o">.</span><span class="n">email</span><span class="p">,</span>
|
||||
<span class="s2">"picture"</span><span class="p">:</span> <span class="n">url_for</span><span class="p">(</span><span class="s2">"static"</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="sa">f</span><span class="s2">"users/</span><span class="si">{</span><span class="nb">id</span><span class="si">}</span><span class="s2">/profile.png"</span><span class="p">),</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you want to return another JSON type, use the
|
||||
<a class="reference internal" href="../api.html#flask.json.jsonify" title="flask.json.jsonify"><code class="xref py py-func docutils literal notranslate"><span class="pre">jsonify()</span></code></a> function, which creates a response object
|
||||
with the given data serialized to JSON.</p>
|
||||
<div class="highlight-python 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">jsonify</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/users"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">user_list</span><span class="p">():</span>
|
||||
<span class="n">users</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">name</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">jsonify</span><span class="p">([</span><span class="n">u</span><span class="o">.</span><span class="n">to_json</span><span class="p">()</span> <span class="k">for</span> <span class="n">u</span> <span class="ow">in</span> <span class="n">users</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It is usually not a good idea to return file data in a JSON response.
|
||||
JSON cannot represent binary data directly, so it must be base64
|
||||
encoded, which can be slow, takes more bandwidth to send, and is not as
|
||||
easy to cache. Instead, serve files using one view, and generate a URL
|
||||
to the desired file to include in the JSON. Then the client can make a
|
||||
separate request to get the linked resource after getting the JSON.</p>
|
||||
</section>
|
||||
<section id="receiving-json-in-views">
|
||||
<h2>Receiving JSON in Views<a class="headerlink" href="#receiving-json-in-views" title="Link to this heading">¶</a></h2>
|
||||
<p>Use the <a class="reference internal" href="../api.html#flask.Request.json" title="flask.Request.json"><code class="xref py py-attr docutils literal notranslate"><span class="pre">json</span></code></a> property of the
|
||||
<a class="reference internal" href="../api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> object to decode the request’s body as JSON. If
|
||||
the body is not valid JSON, or the <code class="docutils literal notranslate"><span class="pre">Content-Type</span></code> header is not set to
|
||||
<code class="docutils literal notranslate"><span class="pre">application/json</span></code>, a 400 Bad Request error will be raised.</p>
|
||||
<div class="highlight-python 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">request</span>
|
||||
<section id="adding-http-method-overrides">
|
||||
<h1>Adding HTTP Method Overrides<a class="headerlink" href="#adding-http-method-overrides" title="Link to this heading">¶</a></h1>
|
||||
<p>Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP
|
||||
methods (such as PATCH). In that case it’s possible to “proxy” HTTP
|
||||
methods through another HTTP method in total violation of the protocol.</p>
|
||||
<p>The way this works is by letting the client do an HTTP POST request and
|
||||
set the <code class="docutils literal notranslate"><span class="pre">X-HTTP-Method-Override</span></code> header. Then the method is replaced
|
||||
with the header value before being passed to Flask.</p>
|
||||
<p>This can be accomplished with an HTTP middleware:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">HTTPMethodOverrideMiddleware</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="n">allowed_methods</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span>
|
||||
<span class="s1">'GET'</span><span class="p">,</span>
|
||||
<span class="s1">'HEAD'</span><span class="p">,</span>
|
||||
<span class="s1">'POST'</span><span class="p">,</span>
|
||||
<span class="s1">'DELETE'</span><span class="p">,</span>
|
||||
<span class="s1">'PUT'</span><span class="p">,</span>
|
||||
<span class="s1">'PATCH'</span><span class="p">,</span>
|
||||
<span class="s1">'OPTIONS'</span>
|
||||
<span class="p">])</span>
|
||||
<span class="n">bodyless_methods</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'HEAD'</span><span class="p">,</span> <span class="s1">'OPTIONS'</span><span class="p">,</span> <span class="s1">'DELETE'</span><span class="p">])</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/user/<int:id>"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">user_update</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">get_or_404</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
|
||||
<span class="n">user</span><span class="o">.</span><span class="n">update_from_json</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">json</span><span class="p">)</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">user</span><span class="o">.</span><span class="n">to_json</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">app</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="n">app</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="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
|
||||
<span class="n">method</span> <span class="o">=</span> <span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'HTTP_X_HTTP_METHOD_OVERRIDE'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">method</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">allowed_methods</span><span class="p">:</span>
|
||||
<span class="n">environ</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">]</span> <span class="o">=</span> <span class="n">method</span>
|
||||
<span class="k">if</span> <span class="n">method</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">bodyless_methods</span><span class="p">:</span>
|
||||
<span class="n">environ</span><span class="p">[</span><span class="s1">'CONTENT_LENGTH'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'0'</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To use this with Flask, wrap the app object with the middleware:</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="n">app</span><span class="o">.</span><span class="n">wsgi_app</span> <span class="o">=</span> <span class="n">HTTPMethodOverrideMiddleware</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">wsgi_app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -260,34 +94,20 @@ the body is not valid JSON, or the <code class="docutils literal notranslate"><s
|
|||
<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="#">JavaScript, <code class="docutils literal notranslate"><span class="pre">fetch</span></code>, and JSON</a><ul>
|
||||
<li><a class="reference internal" href="#rendering-templates">Rendering Templates</a></li>
|
||||
<li><a class="reference internal" href="#generating-urls">Generating URLs</a></li>
|
||||
<li><a class="reference internal" href="#making-a-request-with-fetch">Making a Request with <code class="docutils literal notranslate"><span class="pre">fetch</span></code></a></li>
|
||||
<li><a class="reference internal" href="#following-redirects">Following Redirects</a></li>
|
||||
<li><a class="reference internal" href="#replacing-content">Replacing Content</a></li>
|
||||
<li><a class="reference internal" href="#return-json-from-views">Return JSON from Views</a></li>
|
||||
<li><a class="reference internal" href="#receiving-json-in-views">Receiving JSON in Views</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="flashing.html" title="previous chapter">Message Flashing</a>
|
||||
<li>Next: <a href="lazyloading.html" title="next chapter">Lazily Loading Views</a></ul>
|
||||
<li>Previous: <a href="deferredcallbacks.html" title="previous chapter">Deferred Request Callbacks</a>
|
||||
<li>Next: <a href="requestchecksum.html" title="next chapter">Request Content Checksums</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -311,4 +131,4 @@ the body is not valid JSON, or the <code class="docutils literal notranslate"><s
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>AJAX with jQuery — Flask Documentation (3.2.x)</title>
|
||||
<title>MongoDB with MongoEngine — 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>
|
||||
|
|
@ -14,7 +14,9 @@
|
|||
<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="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Adding a favicon" href="favicon.html" />
|
||||
<link rel="prev" title="Lazily Loading Views" href="lazyloading.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -25,19 +27,114 @@
|
|||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="favicon.html" title="Adding a favicon"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="lazyloading.html" title="Lazily Loading Views"
|
||||
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="">AJAX with jQuery</a></li>
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">MongoDB with MongoEngine</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="ajax-with-jquery">
|
||||
<h1>AJAX with jQuery<a class="headerlink" href="#ajax-with-jquery" title="Link to this heading">¶</a></h1>
|
||||
<p>Obsolete, see <a class="reference internal" href="javascript.html"><span class="doc">JavaScript, fetch, and JSON</span></a> instead.</p>
|
||||
|
||||
<section id="mongodb-with-mongoengine">
|
||||
<h1>MongoDB with MongoEngine<a class="headerlink" href="#mongodb-with-mongoengine" title="Link to this heading">¶</a></h1>
|
||||
<p>Using a document database like MongoDB is a common alternative to
|
||||
relational SQL databases. This pattern shows how to use
|
||||
<a class="reference external" href="http://mongoengine.org">MongoEngine</a>, a document mapper library, to integrate with MongoDB.</p>
|
||||
<p>A running MongoDB server and <a class="reference external" href="https://flask-mongoengine.readthedocs.io">Flask-MongoEngine</a> are required.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">flask</span><span class="o">-</span><span class="n">mongoengine</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="configuration">
|
||||
<h2>Configuration<a class="headerlink" href="#configuration" title="Link to this heading">¶</a></h2>
|
||||
<p>Basic setup can be done by defining <code class="docutils literal notranslate"><span class="pre">MONGODB_SETTINGS</span></code> on
|
||||
<code class="docutils literal notranslate"><span class="pre">app.config</span></code> and creating a <code class="docutils literal notranslate"><span class="pre">MongoEngine</span></code> instance.</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">flask_mongoengine</span><span class="w"> </span><span class="kn">import</span> <span class="n">MongoEngine</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">config</span><span class="p">[</span><span class="s1">'MONGODB_SETTINGS'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"db"</span><span class="p">:</span> <span class="s2">"myapp"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">MongoEngine</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="mapping-documents">
|
||||
<h2>Mapping Documents<a class="headerlink" href="#mapping-documents" title="Link to this heading">¶</a></h2>
|
||||
<p>To declare a model that represents a Mongo document, create a class that
|
||||
inherits from <code class="docutils literal notranslate"><span class="pre">Document</span></code> and declare each of the fields.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">mongoengine</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">me</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">Movie</span><span class="p">(</span><span class="n">me</span><span class="o">.</span><span class="n">Document</span><span class="p">):</span>
|
||||
<span class="n">title</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">year</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">IntField</span><span class="p">()</span>
|
||||
<span class="n">rated</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">()</span>
|
||||
<span class="n">director</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">()</span>
|
||||
<span class="n">actors</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">ListField</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the document has nested fields, use <code class="docutils literal notranslate"><span class="pre">EmbeddedDocument</span></code> to
|
||||
defined the fields of the embedded document and
|
||||
<code class="docutils literal notranslate"><span class="pre">EmbeddedDocumentField</span></code> to declare it on the parent document.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Imdb</span><span class="p">(</span><span class="n">me</span><span class="o">.</span><span class="n">EmbeddedDocument</span><span class="p">):</span>
|
||||
<span class="n">imdb_id</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">()</span>
|
||||
<span class="n">rating</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">DecimalField</span><span class="p">()</span>
|
||||
<span class="n">votes</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">IntField</span><span class="p">()</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">Movie</span><span class="p">(</span><span class="n">me</span><span class="o">.</span><span class="n">Document</span><span class="p">):</span>
|
||||
<span class="o">...</span>
|
||||
<span class="n">imdb</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">EmbeddedDocumentField</span><span class="p">(</span><span class="n">Imdb</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="creating-data">
|
||||
<h2>Creating Data<a class="headerlink" href="#creating-data" title="Link to this heading">¶</a></h2>
|
||||
<p>Instantiate your document class with keyword arguments for the fields.
|
||||
You can also assign values to the field attributes after instantiation.
|
||||
Then call <code class="docutils literal notranslate"><span class="pre">doc.save()</span></code>.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bttf</span> <span class="o">=</span> <span class="n">Movie</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Back To The Future"</span><span class="p">,</span> <span class="n">year</span><span class="o">=</span><span class="mi">1985</span><span class="p">)</span>
|
||||
<span class="n">bttf</span><span class="o">.</span><span class="n">actors</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="s2">"Michael J. Fox"</span><span class="p">,</span>
|
||||
<span class="s2">"Christopher Lloyd"</span>
|
||||
<span class="p">]</span>
|
||||
<span class="n">bttf</span><span class="o">.</span><span class="n">imdb</span> <span class="o">=</span> <span class="n">Imdb</span><span class="p">(</span><span class="n">imdb_id</span><span class="o">=</span><span class="s2">"tt0088763"</span><span class="p">,</span> <span class="n">rating</span><span class="o">=</span><span class="mf">8.5</span><span class="p">)</span>
|
||||
<span class="n">bttf</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="queries">
|
||||
<h2>Queries<a class="headerlink" href="#queries" title="Link to this heading">¶</a></h2>
|
||||
<p>Use the class <code class="docutils literal notranslate"><span class="pre">objects</span></code> attribute to make queries. A keyword argument
|
||||
looks for an equal value on the field.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bttf</span> <span class="o">=</span> <span class="n">Movie</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Back To The Future"</span><span class="p">)</span><span class="o">.</span><span class="n">get_or_404</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Query operators may be used by concatenating them with the field name
|
||||
using a double-underscore. <code class="docutils literal notranslate"><span class="pre">objects</span></code>, and queries returned by
|
||||
calling it, are iterable.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">some_theron_movie</span> <span class="o">=</span> <span class="n">Movie</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">actors__in</span><span class="o">=</span><span class="p">[</span><span class="s2">"Charlize Theron"</span><span class="p">])</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">recents</span> <span class="ow">in</span> <span class="n">Movie</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">year__gte</span><span class="o">=</span><span class="mi">2017</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">recents</span><span class="o">.</span><span class="n">title</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="documentation">
|
||||
<h2>Documentation<a class="headerlink" href="#documentation" title="Link to this heading">¶</a></h2>
|
||||
<p>There are many more ways to define and query documents with MongoEngine.
|
||||
For more information, check out the <a class="reference external" href="http://mongoengine.org">official documentation</a>.</p>
|
||||
<p>Flask-MongoEngine adds helpful utilities on top of MongoEngine. Check
|
||||
out their <a class="reference external" href="https://flask-mongoengine.readthedocs.io">documentation</a> as well.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -48,16 +145,34 @@
|
|||
<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="#">MongoDB with MongoEngine</a><ul>
|
||||
<li><a class="reference internal" href="#configuration">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#mapping-documents">Mapping Documents</a></li>
|
||||
<li><a class="reference internal" href="#creating-data">Creating Data</a></li>
|
||||
<li><a class="reference internal" href="#queries">Queries</a></li>
|
||||
<li><a class="reference internal" href="#documentation">Documentation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="lazyloading.html" title="previous chapter">Lazily Loading Views</a>
|
||||
<li>Next: <a href="favicon.html" title="next chapter">Adding a favicon</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<search id="searchbox" style="display: none" role="search">
|
||||
|
|
@ -79,4 +194,4 @@
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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 — Flask Documentation (3.2.x)</title>
|
||||
<title>Large Applications as Packages — 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> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</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 Google’s 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
|
||||
it’s 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. Let’s 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">"yourapplication"</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">"flask"</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">"flit_core<4"</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">"flit_core.buildapi"</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>Here’s 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">'/'</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">'/user/<username>'</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">'Hello World!'</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">'/'</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">'/user/<username>'</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 (That’s 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">'.'</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>What’s 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 don’t 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">'/'</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">'yourapplication.views.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">'/user/<username>'</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">'yourapplication.views.user'</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">"yourapplication.</span><span class="si">{</span><span class="n">import_name</span><span class="si">}</span><span class="s2">"</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">'views.index'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'/'</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">'/user/'</span><span class="p">,</span><span class="s1">'/user/<username>'</span><span class="p">]</span>
|
||||
<span class="n">url</span><span class="p">(</span><span class="s1">'views.user'</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 it’s 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>
|
||||
|
|
|
|||
|
|
@ -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>Adding HTTP Method Overrides — Flask Documentation (3.2.x)</title>
|
||||
<title>Request Content Checksums — 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="Request Content Checksums" href="requestchecksum.html" />
|
||||
<link rel="prev" title="Deferred Request Callbacks" href="deferredcallbacks.html" />
|
||||
<link rel="next" title="Background Tasks with Celery" href="celery.html" />
|
||||
<link rel="prev" title="Adding HTTP Method Overrides" href="methodoverrides.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,60 +28,72 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="requestchecksum.html" title="Request Content Checksums"
|
||||
<a href="celery.html" title="Background Tasks with Celery"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="deferredcallbacks.html" title="Deferred Request Callbacks"
|
||||
<a href="methodoverrides.html" title="Adding HTTP Method Overrides"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Adding HTTP Method Overrides</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Request Content Checksums</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="adding-http-method-overrides">
|
||||
<h1>Adding HTTP Method Overrides<a class="headerlink" href="#adding-http-method-overrides" title="Link to this heading">¶</a></h1>
|
||||
<p>Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP
|
||||
methods (such as PATCH). In that case it’s possible to “proxy” HTTP
|
||||
methods through another HTTP method in total violation of the protocol.</p>
|
||||
<p>The way this works is by letting the client do an HTTP POST request and
|
||||
set the <code class="docutils literal notranslate"><span class="pre">X-HTTP-Method-Override</span></code> header. Then the method is replaced
|
||||
with the header value before being passed to Flask.</p>
|
||||
<p>This can be accomplished with an HTTP middleware:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">HTTPMethodOverrideMiddleware</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="n">allowed_methods</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span>
|
||||
<span class="s1">'GET'</span><span class="p">,</span>
|
||||
<span class="s1">'HEAD'</span><span class="p">,</span>
|
||||
<span class="s1">'POST'</span><span class="p">,</span>
|
||||
<span class="s1">'DELETE'</span><span class="p">,</span>
|
||||
<span class="s1">'PUT'</span><span class="p">,</span>
|
||||
<span class="s1">'PATCH'</span><span class="p">,</span>
|
||||
<span class="s1">'OPTIONS'</span>
|
||||
<span class="p">])</span>
|
||||
<span class="n">bodyless_methods</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'HEAD'</span><span class="p">,</span> <span class="s1">'OPTIONS'</span><span class="p">,</span> <span class="s1">'DELETE'</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">app</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="n">app</span>
|
||||
<section id="request-content-checksums">
|
||||
<h1>Request Content Checksums<a class="headerlink" href="#request-content-checksums" title="Link to this heading">¶</a></h1>
|
||||
<p>Various pieces of code can consume the request data and preprocess it.
|
||||
For instance JSON data ends up on the request object already read and
|
||||
processed, form data ends up there as well but goes through a different
|
||||
code path. This seems inconvenient when you want to calculate the
|
||||
checksum of the incoming request data. This is necessary sometimes for
|
||||
some APIs.</p>
|
||||
<p>Fortunately this is however very simple to change by wrapping the input
|
||||
stream.</p>
|
||||
<p>The following example calculates the SHA1 checksum of the incoming data as
|
||||
it gets read and stores it in the WSGI environment:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">hashlib</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="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
|
||||
<span class="n">method</span> <span class="o">=</span> <span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'HTTP_X_HTTP_METHOD_OVERRIDE'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">method</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">allowed_methods</span><span class="p">:</span>
|
||||
<span class="n">environ</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">]</span> <span class="o">=</span> <span class="n">method</span>
|
||||
<span class="k">if</span> <span class="n">method</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">bodyless_methods</span><span class="p">:</span>
|
||||
<span class="n">environ</span><span class="p">[</span><span class="s1">'CONTENT_LENGTH'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'0'</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">ChecksumCalcStream</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">stream</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_stream</span> <span class="o">=</span> <span class="n">stream</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_hash</span> <span class="o">=</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">sha1</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="nb">bytes</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_hash</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">rv</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">readline</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">size_hint</span><span class="p">):</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_stream</span><span class="o">.</span><span class="n">readline</span><span class="p">(</span><span class="n">size_hint</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_hash</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">rv</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_checksum</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
|
||||
<span class="n">env</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">environ</span>
|
||||
<span class="n">stream</span> <span class="o">=</span> <span class="n">ChecksumCalcStream</span><span class="p">(</span><span class="n">env</span><span class="p">[</span><span class="s1">'wsgi.input'</span><span class="p">])</span>
|
||||
<span class="n">env</span><span class="p">[</span><span class="s1">'wsgi.input'</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span>
|
||||
<span class="k">return</span> <span class="n">stream</span><span class="o">.</span><span class="n">_hash</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To use this with Flask, wrap the app object with the middleware:</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="n">app</span><span class="o">.</span><span class="n">wsgi_app</span> <span class="o">=</span> <span class="n">HTTPMethodOverrideMiddleware</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">wsgi_app</span><span class="p">)</span>
|
||||
<p>To use this, all you need to do is to hook the calculating stream in
|
||||
before the request starts consuming data. (Eg: be careful accessing
|
||||
<code class="docutils literal notranslate"><span class="pre">request.form</span></code> or anything of that nature. <code class="docutils literal notranslate"><span class="pre">before_request_handlers</span></code>
|
||||
for instance should be careful not to access it).</p>
|
||||
<p>Example usage:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/special-api'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">special_api</span><span class="p">():</span>
|
||||
<span class="nb">hash</span> <span class="o">=</span> <span class="n">generate_checksum</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
|
||||
<span class="c1"># Accessing this parses the input stream</span>
|
||||
<span class="n">files</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span>
|
||||
<span class="c1"># At this point the hash is fully constructed.</span>
|
||||
<span class="n">checksum</span> <span class="o">=</span> <span class="nb">hash</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Hash was: </span><span class="si">{</span><span class="n">checksum</span><span class="si">}</span><span class="s2">"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -94,20 +106,20 @@ with the header value before being passed to Flask.</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>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="deferredcallbacks.html" title="previous chapter">Deferred Request Callbacks</a>
|
||||
<li>Next: <a href="requestchecksum.html" title="next chapter">Request Content Checksums</a></ul>
|
||||
<li>Previous: <a href="methodoverrides.html" title="previous chapter">Adding HTTP Method Overrides</a>
|
||||
<li>Next: <a href="celery.html" title="next chapter">Background Tasks with Celery</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -131,4 +143,4 @@ with the header value before being passed to Flask.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>MongoDB with MongoEngine — Flask Documentation (3.2.x)</title>
|
||||
<title>Single-Page Applications — 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="Adding a favicon" href="favicon.html" />
|
||||
<link rel="prev" title="Lazily Loading Views" href="lazyloading.html" />
|
||||
<link rel="next" title="Security Considerations" href="../web-security.html" />
|
||||
<link rel="prev" title="Subclassing Flask" href="subclassing.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,113 +28,45 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="favicon.html" title="Adding a favicon"
|
||||
<a href="../web-security.html" title="Security Considerations"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="lazyloading.html" title="Lazily Loading Views"
|
||||
<a href="subclassing.html" title="Subclassing Flask"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">MongoDB with MongoEngine</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Single-Page Applications</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="mongodb-with-mongoengine">
|
||||
<h1>MongoDB with MongoEngine<a class="headerlink" href="#mongodb-with-mongoengine" title="Link to this heading">¶</a></h1>
|
||||
<p>Using a document database like MongoDB is a common alternative to
|
||||
relational SQL databases. This pattern shows how to use
|
||||
<a class="reference external" href="http://mongoengine.org">MongoEngine</a>, a document mapper library, to integrate with MongoDB.</p>
|
||||
<p>A running MongoDB server and <a class="reference external" href="https://flask-mongoengine.readthedocs.io">Flask-MongoEngine</a> are required.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">flask</span><span class="o">-</span><span class="n">mongoengine</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="configuration">
|
||||
<h2>Configuration<a class="headerlink" href="#configuration" title="Link to this heading">¶</a></h2>
|
||||
<p>Basic setup can be done by defining <code class="docutils literal notranslate"><span class="pre">MONGODB_SETTINGS</span></code> on
|
||||
<code class="docutils literal notranslate"><span class="pre">app.config</span></code> and creating a <code class="docutils literal notranslate"><span class="pre">MongoEngine</span></code> instance.</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">flask_mongoengine</span><span class="w"> </span><span class="kn">import</span> <span class="n">MongoEngine</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">config</span><span class="p">[</span><span class="s1">'MONGODB_SETTINGS'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"db"</span><span class="p">:</span> <span class="s2">"myapp"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">MongoEngine</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="mapping-documents">
|
||||
<h2>Mapping Documents<a class="headerlink" href="#mapping-documents" title="Link to this heading">¶</a></h2>
|
||||
<p>To declare a model that represents a Mongo document, create a class that
|
||||
inherits from <code class="docutils literal notranslate"><span class="pre">Document</span></code> and declare each of the fields.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">mongoengine</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">me</span>
|
||||
<section id="single-page-applications">
|
||||
<h1>Single-Page Applications<a class="headerlink" href="#single-page-applications" title="Link to this heading">¶</a></h1>
|
||||
<p>Flask can be used to serve Single-Page Applications (SPA) by placing static
|
||||
files produced by your frontend framework in a subfolder inside of your
|
||||
project. You will also need to create a catch-all endpoint that routes all
|
||||
requests to your SPA.</p>
|
||||
<p>The following example demonstrates how to serve an SPA along with an API:</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="p">,</span> <span class="n">jsonify</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">Movie</span><span class="p">(</span><span class="n">me</span><span class="o">.</span><span class="n">Document</span><span class="p">):</span>
|
||||
<span class="n">title</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">year</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">IntField</span><span class="p">()</span>
|
||||
<span class="n">rated</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">()</span>
|
||||
<span class="n">director</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">()</span>
|
||||
<span class="n">actors</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">ListField</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the document has nested fields, use <code class="docutils literal notranslate"><span class="pre">EmbeddedDocument</span></code> to
|
||||
defined the fields of the embedded document and
|
||||
<code class="docutils literal notranslate"><span class="pre">EmbeddedDocumentField</span></code> to declare it on the parent document.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Imdb</span><span class="p">(</span><span class="n">me</span><span class="o">.</span><span class="n">EmbeddedDocument</span><span class="p">):</span>
|
||||
<span class="n">imdb_id</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">StringField</span><span class="p">()</span>
|
||||
<span class="n">rating</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">DecimalField</span><span class="p">()</span>
|
||||
<span class="n">votes</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">IntField</span><span class="p">()</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">static_folder</span><span class="o">=</span><span class="s1">'app'</span><span class="p">,</span> <span class="n">static_url_path</span><span class="o">=</span><span class="s2">"/app"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">Movie</span><span class="p">(</span><span class="n">me</span><span class="o">.</span><span class="n">Document</span><span class="p">):</span>
|
||||
<span class="o">...</span>
|
||||
<span class="n">imdb</span> <span class="o">=</span> <span class="n">me</span><span class="o">.</span><span class="n">EmbeddedDocumentField</span><span class="p">(</span><span class="n">Imdb</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="creating-data">
|
||||
<h2>Creating Data<a class="headerlink" href="#creating-data" title="Link to this heading">¶</a></h2>
|
||||
<p>Instantiate your document class with keyword arguments for the fields.
|
||||
You can also assign values to the field attributes after instantiation.
|
||||
Then call <code class="docutils literal notranslate"><span class="pre">doc.save()</span></code>.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bttf</span> <span class="o">=</span> <span class="n">Movie</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Back To The Future"</span><span class="p">,</span> <span class="n">year</span><span class="o">=</span><span class="mi">1985</span><span class="p">)</span>
|
||||
<span class="n">bttf</span><span class="o">.</span><span class="n">actors</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="s2">"Michael J. Fox"</span><span class="p">,</span>
|
||||
<span class="s2">"Christopher Lloyd"</span>
|
||||
<span class="p">]</span>
|
||||
<span class="n">bttf</span><span class="o">.</span><span class="n">imdb</span> <span class="o">=</span> <span class="n">Imdb</span><span class="p">(</span><span class="n">imdb_id</span><span class="o">=</span><span class="s2">"tt0088763"</span><span class="p">,</span> <span class="n">rating</span><span class="o">=</span><span class="mf">8.5</span><span class="p">)</span>
|
||||
<span class="n">bttf</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="queries">
|
||||
<h2>Queries<a class="headerlink" href="#queries" title="Link to this heading">¶</a></h2>
|
||||
<p>Use the class <code class="docutils literal notranslate"><span class="pre">objects</span></code> attribute to make queries. A keyword argument
|
||||
looks for an equal value on the field.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bttf</span> <span class="o">=</span> <span class="n">Movie</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Back To The Future"</span><span class="p">)</span><span class="o">.</span><span class="n">get_or_404</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Query operators may be used by concatenating them with the field name
|
||||
using a double-underscore. <code class="docutils literal notranslate"><span class="pre">objects</span></code>, and queries returned by
|
||||
calling it, are iterable.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">some_theron_movie</span> <span class="o">=</span> <span class="n">Movie</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">actors__in</span><span class="o">=</span><span class="p">[</span><span class="s2">"Charlize Theron"</span><span class="p">])</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">recents</span> <span class="ow">in</span> <span class="n">Movie</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">year__gte</span><span class="o">=</span><span class="mi">2017</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">recents</span><span class="o">.</span><span class="n">title</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="s2">"/heartbeat"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">heartbeat</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">jsonify</span><span class="p">({</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"healthy"</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="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="s1">'path'</span><span class="p">:</span> <span class="s1">''</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">'/<path:path>'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">catch_all</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">app</span><span class="o">.</span><span class="n">send_static_file</span><span class="p">(</span><span class="s2">"index.html"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="documentation">
|
||||
<h2>Documentation<a class="headerlink" href="#documentation" title="Link to this heading">¶</a></h2>
|
||||
<p>There are many more ways to define and query documents with MongoEngine.
|
||||
For more information, check out the <a class="reference external" href="http://mongoengine.org">official documentation</a>.</p>
|
||||
<p>Flask-MongoEngine adds helpful utilities on top of MongoEngine. Check
|
||||
out their <a class="reference external" href="https://flask-mongoengine.readthedocs.io">documentation</a> as well.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -145,32 +77,20 @@ out their <a class="reference external" href="https://flask-mongoengine.readthed
|
|||
<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="#">MongoDB with MongoEngine</a><ul>
|
||||
<li><a class="reference internal" href="#configuration">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#mapping-documents">Mapping Documents</a></li>
|
||||
<li><a class="reference internal" href="#creating-data">Creating Data</a></li>
|
||||
<li><a class="reference internal" href="#queries">Queries</a></li>
|
||||
<li><a class="reference internal" href="#documentation">Documentation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="lazyloading.html" title="previous chapter">Lazily Loading Views</a>
|
||||
<li>Next: <a href="favicon.html" title="next chapter">Adding a favicon</a></ul>
|
||||
<li>Previous: <a href="subclassing.html" title="previous chapter">Subclassing Flask</a>
|
||||
<li>Next: <a href="../web-security.html" title="next chapter">Security Considerations</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -194,4 +114,4 @@ out their <a class="reference external" href="https://flask-mongoengine.readthed
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Large Applications as Packages — Flask Documentation (3.2.x)</title>
|
||||
<title>SQLAlchemy 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>
|
||||
|
|
@ -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="Application Factories" href="appfactories.html" />
|
||||
<link rel="prev" title="Patterns for Flask" href="index.html" />
|
||||
<link rel="next" title="Uploading Files" href="fileuploads.html" />
|
||||
<link rel="prev" title="Using SQLite 3 with Flask" href="sqlite3.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,144 +28,217 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="appfactories.html" title="Application Factories"
|
||||
<a href="fileuploads.html" title="Uploading Files"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="index.html" title="Patterns for Flask"
|
||||
<a href="sqlite3.html" title="Using SQLite 3 with Flask"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Large Applications as Packages</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">SQLAlchemy in Flask</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<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
|
||||
it’s 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. Let’s 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">"yourapplication"</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">"flask"</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">"flit_core<4"</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">"flit_core.buildapi"</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>Here’s 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>
|
||||
<section id="sqlalchemy-in-flask">
|
||||
<h1>SQLAlchemy in Flask<a class="headerlink" href="#sqlalchemy-in-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>Many people prefer <a class="reference external" href="https://www.sqlalchemy.org/">SQLAlchemy</a> for database access. In this case it’s
|
||||
encouraged to use a package instead of a module for your flask application
|
||||
and drop the models into a separate module (<a class="reference internal" href="packages.html"><span class="doc">Large Applications as Packages</span></a>). While that
|
||||
is not necessary, it makes a lot of sense.</p>
|
||||
<p>There are four very common ways to use SQLAlchemy. I will outline each
|
||||
of them here:</p>
|
||||
<section id="flask-sqlalchemy-extension">
|
||||
<h2>Flask-SQLAlchemy Extension<a class="headerlink" href="#flask-sqlalchemy-extension" title="Link to this heading">¶</a></h2>
|
||||
<p>Because SQLAlchemy is a common database abstraction layer and object
|
||||
relational mapper that requires a little bit of configuration effort,
|
||||
there is a Flask extension that handles that for you. This is recommended
|
||||
if you want to get started quickly.</p>
|
||||
<p>You can download <a class="reference external" href="https://flask-sqlalchemy.palletsprojects.com/">Flask-SQLAlchemy</a> from <a class="reference external" href="https://pypi.org/project/Flask-SQLAlchemy/">PyPI</a>.</p>
|
||||
</section>
|
||||
<section id="declarative">
|
||||
<h2>Declarative<a class="headerlink" href="#declarative" title="Link to this heading">¶</a></h2>
|
||||
<p>The declarative extension in SQLAlchemy is the most recent method of using
|
||||
SQLAlchemy. It allows you to define tables and models in one go, similar
|
||||
to how Django works. In addition to the following text I recommend the
|
||||
official documentation on the <a class="reference external" href="https://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/">declarative</a> extension.</p>
|
||||
<p>Here’s the example <code class="file docutils literal notranslate"><span class="pre">database.py</span></code> module for your application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_engine</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">scoped_session</span><span class="p">,</span> <span class="n">sessionmaker</span><span class="p">,</span> <span class="n">declarative_base</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="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite:////tmp/test.db'</span><span class="p">)</span>
|
||||
<span class="n">db_session</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">autocommit</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">autoflush</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">))</span>
|
||||
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span>
|
||||
<span class="n">Base</span><span class="o">.</span><span class="n">query</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query_property</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>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">init_db</span><span class="p">():</span>
|
||||
<span class="c1"># import all modules here that might define models so that</span>
|
||||
<span class="c1"># they will be registered properly on the metadata. Otherwise</span>
|
||||
<span class="c1"># you will have to import them first before calling init_db()</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">yourapplication.models</span>
|
||||
<span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<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>
|
||||
<p>To define your models, just subclass the <code class="code docutils literal notranslate"><span class="pre">Base</span></code> class that was created by
|
||||
the code above. If you are wondering why we don’t have to care about
|
||||
threads here (like we did in the SQLite3 example above with the
|
||||
<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> object): that’s because SQLAlchemy does that for us
|
||||
already with the <a class="reference external" href="https://docs.sqlalchemy.org/en/20/orm/contextual.html#sqlalchemy.orm.scoped_session" title="(in SQLAlchemy v2.0)"><code class="xref py py-class docutils literal notranslate"><span class="pre">scoped_session</span></code></a>.</p>
|
||||
<p>To use SQLAlchemy in a declarative way with your application, you just
|
||||
have to put the following code into your application module. Flask will
|
||||
automatically remove database sessions at the end of the request or
|
||||
when the application shuts down:</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.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_session</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_appcontext</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">shutdown_session</span><span class="p">(</span><span class="n">exception</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="n">db_session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</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 (That’s 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>
|
||||
<p>Here is an example model (put this into <code class="file docutils literal notranslate"><span class="pre">models.py</span></code>, e.g.):</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">Base</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">User</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
|
||||
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'users'</span>
|
||||
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">email</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</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">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s1">'<User </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">!r}</span><span class="s1">>'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To create the database you can use the <code class="code docutils literal notranslate"><span class="pre">init_db</span></code> function:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">init_db</span>
|
||||
<span class="gp">>>> </span><span class="n">init_db</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can insert entries into the database like this:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_session</span>
|
||||
<span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="s1">'admin'</span><span class="p">,</span> <span class="s1">'admin@localhost'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">u</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">db_session</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Querying is simple as well:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||||
<span class="go">[<User 'admin'>]</span>
|
||||
<span class="gp">>>> </span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s1">'admin'</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="go"><User 'admin'></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<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 it’s 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 id="manual-object-relational-mapping">
|
||||
<h2>Manual Object Relational Mapping<a class="headerlink" href="#manual-object-relational-mapping" title="Link to this heading">¶</a></h2>
|
||||
<p>Manual object relational mapping has a few upsides and a few downsides
|
||||
versus the declarative approach from above. The main difference is that
|
||||
you define tables and classes separately and map them together. It’s more
|
||||
flexible but a little more to type. In general it works like the
|
||||
declarative approach, so make sure to also split up your application into
|
||||
multiple modules in a package.</p>
|
||||
<p>Here is an example <code class="file docutils literal notranslate"><span class="pre">database.py</span></code> module for your application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">scoped_session</span><span class="p">,</span> <span class="n">sessionmaker</span>
|
||||
|
||||
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite:////tmp/test.db'</span><span class="p">)</span>
|
||||
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span>
|
||||
<span class="n">db_session</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">autocommit</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">autoflush</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">))</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">init_db</span><span class="p">():</span>
|
||||
<span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As in the declarative approach, you need to close the session after
|
||||
each request or application context shutdown. Put this into your
|
||||
application module:</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.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_session</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_appcontext</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">shutdown_session</span><span class="p">(</span><span class="n">exception</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="n">db_session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here is an example table and model (put this into <code class="file docutils literal notranslate"><span class="pre">models.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">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">Table</span><span class="p">,</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">mapper</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">db_session</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">User</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="n">query</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query_property</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">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s1">'<User </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">!r}</span><span class="s1">>'</span>
|
||||
|
||||
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span>
|
||||
<span class="n">Column</span><span class="p">(</span><span class="s1">'id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span>
|
||||
<span class="n">Column</span><span class="p">(</span><span class="s1">'name'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span>
|
||||
<span class="n">Column</span><span class="p">(</span><span class="s1">'email'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">mapper</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">users</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Querying and inserting works exactly the same as in the example above.</p>
|
||||
</section>
|
||||
<section id="sql-abstraction-layer">
|
||||
<h2>SQL Abstraction Layer<a class="headerlink" href="#sql-abstraction-layer" title="Link to this heading">¶</a></h2>
|
||||
<p>If you just want to use the database system (and SQL) abstraction layer
|
||||
you basically only need the engine:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span><span class="p">,</span> <span class="n">Table</span>
|
||||
|
||||
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite:////tmp/test.db'</span><span class="p">)</span>
|
||||
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Then you can either declare the tables in your code like in the examples
|
||||
above, or automatically load them:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">Table</span>
|
||||
|
||||
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">autoload</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To insert data you can use the <code class="code docutils literal notranslate"><span class="pre">insert</span></code> method. We have to get a
|
||||
connection first so that we can use a transaction:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">con</span> <span class="o">=</span> <span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
|
||||
<span class="gp">>>> </span><span class="n">con</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">insert</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s1">'admin@localhost'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>SQLAlchemy will automatically commit for us.</p>
|
||||
<p>To query your database, you use the engine directly or use a connection:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">users</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="go">(1, 'admin', 'admin@localhost')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>These results are also dict-like tuples:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span>
|
||||
<span class="go">'admin'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also pass strings of SQL statements to the
|
||||
<code class="xref py py-meth docutils literal notranslate"><span class="pre">execute()</span></code> method:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">engine</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s1">'select * from users where id = :1'</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="go">(1, 'admin', 'admin@localhost')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For more information about SQLAlchemy, head over to the
|
||||
<a class="reference external" href="https://www.sqlalchemy.org/">website</a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -177,18 +250,20 @@ blueprint. For a gentle introduction into this topic refer to the
|
|||
<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="#">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>
|
||||
<li><a class="reference internal" href="#">SQLAlchemy in Flask</a><ul>
|
||||
<li><a class="reference internal" href="#flask-sqlalchemy-extension">Flask-SQLAlchemy Extension</a></li>
|
||||
<li><a class="reference internal" href="#declarative">Declarative</a></li>
|
||||
<li><a class="reference internal" href="#manual-object-relational-mapping">Manual Object Relational Mapping</a></li>
|
||||
<li><a class="reference internal" href="#sql-abstraction-layer">SQL Abstraction Layer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -198,8 +273,8 @@ blueprint. For a gentle introduction into this topic refer to the
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</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>Previous: <a href="sqlite3.html" title="previous chapter">Using SQLite 3 with Flask</a>
|
||||
<li>Next: <a href="fileuploads.html" title="next chapter">Uploading Files</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -223,4 +298,4 @@ blueprint. For a gentle introduction into this topic refer to the
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Request Content Checksums — Flask Documentation (3.2.x)</title>
|
||||
<title>Using SQLite 3 with 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>
|
||||
|
|
@ -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="Background Tasks with Celery" href="celery.html" />
|
||||
<link rel="prev" title="Adding HTTP Method Overrides" href="methodoverrides.html" />
|
||||
<link rel="next" title="SQLAlchemy in Flask" href="sqlalchemy.html" />
|
||||
<link rel="prev" title="Using URL Processors" href="urlprocessors.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,74 +28,162 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="celery.html" title="Background Tasks with Celery"
|
||||
<a href="sqlalchemy.html" title="SQLAlchemy in Flask"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="methodoverrides.html" title="Adding HTTP Method Overrides"
|
||||
<a href="urlprocessors.html" title="Using URL Processors"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Request Content Checksums</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Using SQLite 3 with Flask</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="request-content-checksums">
|
||||
<h1>Request Content Checksums<a class="headerlink" href="#request-content-checksums" title="Link to this heading">¶</a></h1>
|
||||
<p>Various pieces of code can consume the request data and preprocess it.
|
||||
For instance JSON data ends up on the request object already read and
|
||||
processed, form data ends up there as well but goes through a different
|
||||
code path. This seems inconvenient when you want to calculate the
|
||||
checksum of the incoming request data. This is necessary sometimes for
|
||||
some APIs.</p>
|
||||
<p>Fortunately this is however very simple to change by wrapping the input
|
||||
stream.</p>
|
||||
<p>The following example calculates the SHA1 checksum of the incoming data as
|
||||
it gets read and stores it in the WSGI environment:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">hashlib</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">ChecksumCalcStream</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<section id="using-sqlite-3-with-flask">
|
||||
<h1>Using SQLite 3 with Flask<a class="headerlink" href="#using-sqlite-3-with-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>In Flask you can easily implement the opening of database connections on
|
||||
demand and closing them when the context dies (usually at the end of the
|
||||
request).</p>
|
||||
<p>Here is a simple example of how you can use SQLite 3 with Flask:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">sqlite3</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">g</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">stream</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_stream</span> <span class="o">=</span> <span class="n">stream</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_hash</span> <span class="o">=</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">sha1</span><span class="p">()</span>
|
||||
<span class="n">DATABASE</span> <span class="o">=</span> <span class="s1">'/path/to/database.db'</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="nb">bytes</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_hash</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">rv</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">get_db</span><span class="p">():</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s1">'_database'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">db</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">_database</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">DATABASE</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">db</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">readline</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">size_hint</span><span class="p">):</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_stream</span><span class="o">.</span><span class="n">readline</span><span class="p">(</span><span class="n">size_hint</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_hash</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">rv</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_checksum</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
|
||||
<span class="n">env</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">environ</span>
|
||||
<span class="n">stream</span> <span class="o">=</span> <span class="n">ChecksumCalcStream</span><span class="p">(</span><span class="n">env</span><span class="p">[</span><span class="s1">'wsgi.input'</span><span class="p">])</span>
|
||||
<span class="n">env</span><span class="p">[</span><span class="s1">'wsgi.input'</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span>
|
||||
<span class="k">return</span> <span class="n">stream</span><span class="o">.</span><span class="n">_hash</span>
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_appcontext</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">close_connection</span><span class="p">(</span><span class="n">exception</span><span class="p">):</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s1">'_database'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">db</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To use this, all you need to do is to hook the calculating stream in
|
||||
before the request starts consuming data. (Eg: be careful accessing
|
||||
<code class="docutils literal notranslate"><span class="pre">request.form</span></code> or anything of that nature. <code class="docutils literal notranslate"><span class="pre">before_request_handlers</span></code>
|
||||
for instance should be careful not to access it).</p>
|
||||
<p>Example usage:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/special-api'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">special_api</span><span class="p">():</span>
|
||||
<span class="nb">hash</span> <span class="o">=</span> <span class="n">generate_checksum</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
|
||||
<span class="c1"># Accessing this parses the input stream</span>
|
||||
<span class="n">files</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span>
|
||||
<span class="c1"># At this point the hash is fully constructed.</span>
|
||||
<span class="n">checksum</span> <span class="o">=</span> <span class="nb">hash</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Hash was: </span><span class="si">{</span><span class="n">checksum</span><span class="si">}</span><span class="s2">"</span>
|
||||
<p>Now, to use the database, the application must either have an active
|
||||
application context (which is always true if there is a request in flight)
|
||||
or create an application context itself. At that point the <code class="docutils literal notranslate"><span class="pre">get_db</span></code>
|
||||
function can be used to get the current database connection. Whenever the
|
||||
context is destroyed the database connection will be terminated.</p>
|
||||
<p>Example:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="n">cur</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Please keep in mind that the teardown request and appcontext functions
|
||||
are always executed, even if a before-request handler failed or was
|
||||
never executed. Because of this we have to make sure here that the
|
||||
database is there before we close it.</p>
|
||||
</div>
|
||||
<section id="connect-on-demand">
|
||||
<h2>Connect on Demand<a class="headerlink" href="#connect-on-demand" title="Link to this heading">¶</a></h2>
|
||||
<p>The upside of this approach (connecting on first use) is that this will
|
||||
only open the connection if truly necessary. If you want to use this
|
||||
code outside a request context you can use it in a Python shell by opening
|
||||
the application context by hand:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">app_context</span><span class="p">():</span>
|
||||
<span class="c1"># now you can use get_db()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="easy-querying">
|
||||
<h2>Easy Querying<a class="headerlink" href="#easy-querying" title="Link to this heading">¶</a></h2>
|
||||
<p>Now in each request handling function you can access <code class="code docutils literal notranslate"><span class="pre">get_db()</span></code> to get the
|
||||
current open database connection. To simplify working with SQLite, a
|
||||
row factory function is useful. It is executed for every result returned
|
||||
from the database to convert the result. For instance, in order to get
|
||||
dictionaries instead of tuples, this could be inserted into the <code class="docutils literal notranslate"><span class="pre">get_db</span></code>
|
||||
function we created above:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">make_dicts</span><span class="p">(</span><span class="n">cursor</span><span class="p">,</span> <span class="n">row</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="nb">dict</span><span class="p">((</span><span class="n">cursor</span><span class="o">.</span><span class="n">description</span><span class="p">[</span><span class="n">idx</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">value</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">row</span><span class="p">))</span>
|
||||
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">make_dicts</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will make the sqlite3 module return dicts for this database connection, which are much nicer to deal with. Even more simply, we could place this in <code class="docutils literal notranslate"><span class="pre">get_db</span></code> instead:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">db</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This would use Row objects rather than dicts to return the results of queries. These are <code class="docutils literal notranslate"><span class="pre">namedtuple</span></code> s, so we can access them either by index or by key. For example, assuming we have a <code class="docutils literal notranslate"><span class="pre">sqlite3.Row</span></code> called <code class="docutils literal notranslate"><span class="pre">r</span></code> for the rows <code class="docutils literal notranslate"><span class="pre">id</span></code>, <code class="docutils literal notranslate"><span class="pre">FirstName</span></code>, <code class="docutils literal notranslate"><span class="pre">LastName</span></code>, and <code class="docutils literal notranslate"><span class="pre">MiddleInitial</span></code>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="c1"># You can get values based on the row's name</span>
|
||||
<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="s1">'FirstName'</span><span class="p">]</span>
|
||||
<span class="go">John</span>
|
||||
<span class="gp">>>> </span><span class="c1"># Or, you can get them based on index</span>
|
||||
<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="go">John</span>
|
||||
<span class="go"># Row objects are also iterable:</span>
|
||||
<span class="gp">>>> </span><span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">r</span><span class="p">:</span>
|
||||
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||||
<span class="go">1</span>
|
||||
<span class="go">John</span>
|
||||
<span class="go">Doe</span>
|
||||
<span class="go">M</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Additionally, it is a good idea to provide a query function that combines
|
||||
getting the cursor, executing and fetching the results:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">query_db</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(),</span> <span class="n">one</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
<span class="n">cur</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
|
||||
<span class="n">cur</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="p">(</span><span class="n">rv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">rv</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">one</span> <span class="k">else</span> <span class="n">rv</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This handy little function, in combination with a row factory, makes
|
||||
working with the database much more pleasant than it is by just using the
|
||||
raw cursor and connection objects.</p>
|
||||
<p>Here is how you can use it:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">query_db</span><span class="p">(</span><span class="s1">'select * from users'</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">user</span><span class="p">[</span><span class="s1">'username'</span><span class="p">],</span> <span class="s1">'has the id'</span><span class="p">,</span> <span class="n">user</span><span class="p">[</span><span class="s1">'user_id'</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or if you just want a single result:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="n">query_db</span><span class="p">(</span><span class="s1">'select * from users where username = ?'</span><span class="p">,</span>
|
||||
<span class="p">[</span><span class="n">the_username</span><span class="p">],</span> <span class="n">one</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'No such user'</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">the_username</span><span class="p">,</span> <span class="s1">'has the id'</span><span class="p">,</span> <span class="n">user</span><span class="p">[</span><span class="s1">'user_id'</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To pass variable parts to the SQL statement, use a question mark in the
|
||||
statement and pass in the arguments as a list. Never directly add them to
|
||||
the SQL statement with string formatting because this makes it possible
|
||||
to attack the application using <a class="reference external" href="https://en.wikipedia.org/wiki/SQL_injection">SQL Injections</a>.</p>
|
||||
</section>
|
||||
<section id="initial-schemas">
|
||||
<h2>Initial Schemas<a class="headerlink" href="#initial-schemas" title="Link to this heading">¶</a></h2>
|
||||
<p>Relational databases need schemas, so applications often ship a
|
||||
<code class="code docutils literal notranslate"><span class="pre">schema.sql</span></code> file that creates the database. It’s a good idea to provide
|
||||
a function that creates the database based on that schema. This function
|
||||
can do that for you:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">init_db</span><span class="p">():</span>
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">app_context</span><span class="p">():</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span>
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">open_resource</span><span class="p">(</span><span class="s1">'schema.sql'</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span><span class="o">.</span><span class="n">executescript</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can then create such a database from the Python shell:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </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">init_db</span>
|
||||
<span class="gp">>>> </span><span class="n">init_db</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -106,20 +194,30 @@ for instance should be careful not to access it).</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="#">Using SQLite 3 with Flask</a><ul>
|
||||
<li><a class="reference internal" href="#connect-on-demand">Connect on Demand</a></li>
|
||||
<li><a class="reference internal" href="#easy-querying">Easy Querying</a></li>
|
||||
<li><a class="reference internal" href="#initial-schemas">Initial Schemas</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="methodoverrides.html" title="previous chapter">Adding HTTP Method Overrides</a>
|
||||
<li>Next: <a href="celery.html" title="next chapter">Background Tasks with Celery</a></ul>
|
||||
<li>Previous: <a href="urlprocessors.html" title="previous chapter">Using URL Processors</a>
|
||||
<li>Next: <a href="sqlalchemy.html" title="next chapter">SQLAlchemy in Flask</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -143,4 +241,4 @@ for instance should be careful not to access it).</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Single-Page Applications — Flask Documentation (3.2.x)</title>
|
||||
<title>Streaming Contents — 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="Security Considerations" href="../web-security.html" />
|
||||
<link rel="prev" title="Subclassing Flask" href="subclassing.html" />
|
||||
<link rel="next" title="Deferred Request Callbacks" href="deferredcallbacks.html" />
|
||||
<link rel="prev" title="Adding a favicon" href="favicon.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,45 +28,94 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../web-security.html" title="Security Considerations"
|
||||
<a href="deferredcallbacks.html" title="Deferred Request Callbacks"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="subclassing.html" title="Subclassing Flask"
|
||||
<a href="favicon.html" title="Adding a favicon"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Single-Page Applications</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Streaming Contents</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="single-page-applications">
|
||||
<h1>Single-Page Applications<a class="headerlink" href="#single-page-applications" title="Link to this heading">¶</a></h1>
|
||||
<p>Flask can be used to serve Single-Page Applications (SPA) by placing static
|
||||
files produced by your frontend framework in a subfolder inside of your
|
||||
project. You will also need to create a catch-all endpoint that routes all
|
||||
requests to your SPA.</p>
|
||||
<p>The following example demonstrates how to serve an SPA along with an API:</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="p">,</span> <span class="n">jsonify</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">static_folder</span><span class="o">=</span><span class="s1">'app'</span><span class="p">,</span> <span class="n">static_url_path</span><span class="o">=</span><span class="s2">"/app"</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="s2">"/heartbeat"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">heartbeat</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">jsonify</span><span class="p">({</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"healthy"</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="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="s1">'path'</span><span class="p">:</span> <span class="s1">''</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">'/<path:path>'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">catch_all</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">app</span><span class="o">.</span><span class="n">send_static_file</span><span class="p">(</span><span class="s2">"index.html"</span><span class="p">)</span>
|
||||
<section id="streaming-contents">
|
||||
<h1>Streaming Contents<a class="headerlink" href="#streaming-contents" title="Link to this heading">¶</a></h1>
|
||||
<p>Sometimes you want to send an enormous amount of data to the client, much
|
||||
more than you want to keep in memory. When you are generating the data on
|
||||
the fly though, how do you send that back to the client without the
|
||||
roundtrip to the filesystem?</p>
|
||||
<p>The answer is by using generators and direct responses.</p>
|
||||
<section id="basic-usage">
|
||||
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Link to this heading">¶</a></h2>
|
||||
<p>This is a basic view function that generates a lot of CSV data on the fly.
|
||||
The trick is to have an inner function that uses a generator to generate
|
||||
data and to then invoke that function and pass it to a response object:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/large.csv'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_large_csv</span><span class="p">():</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate</span><span class="p">():</span>
|
||||
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">iter_all_rows</span><span class="p">():</span>
|
||||
<span class="k">yield</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="s1">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">)</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span>
|
||||
<span class="k">return</span> <span class="n">generate</span><span class="p">(),</span> <span class="p">{</span><span class="s2">"Content-Type"</span><span class="p">:</span> <span class="s2">"text/csv"</span><span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Each <code class="docutils literal notranslate"><span class="pre">yield</span></code> expression is directly sent to the browser. Note though
|
||||
that some WSGI middlewares might break streaming, so be careful there in
|
||||
debug environments with profilers and other things you might have enabled.</p>
|
||||
</section>
|
||||
<section id="streaming-from-templates">
|
||||
<h2>Streaming from Templates<a class="headerlink" href="#streaming-from-templates" title="Link to this heading">¶</a></h2>
|
||||
<p>The Jinja2 template engine supports rendering a template piece by
|
||||
piece, returning an iterator of strings. Flask provides the
|
||||
<a class="reference internal" href="../api.html#flask.stream_template" title="flask.stream_template"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template()</span></code></a> and <a class="reference internal" href="../api.html#flask.stream_template_string" title="flask.stream_template_string"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template_string()</span></code></a>
|
||||
functions to make this easier to use.</p>
|
||||
<div class="highlight-python 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">stream_template</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/timeline"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">timeline</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">stream_template</span><span class="p">(</span><span class="s2">"timeline.html"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The parts yielded by the render stream tend to match statement blocks in
|
||||
the template.</p>
|
||||
</section>
|
||||
<section id="streaming-with-context">
|
||||
<h2>Streaming with Context<a class="headerlink" href="#streaming-with-context" title="Link to this heading">¶</a></h2>
|
||||
<p>The <a class="reference internal" href="../api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> will not be active while the generator is
|
||||
running, because the view has already returned at that point. If you try
|
||||
to access <code class="docutils literal notranslate"><span class="pre">request</span></code>, you’ll get a <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>.</p>
|
||||
<p>If your generator function relies on data in <code class="docutils literal notranslate"><span class="pre">request</span></code>, use the
|
||||
<a class="reference internal" href="../api.html#flask.stream_with_context" title="flask.stream_with_context"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_with_context()</span></code></a> wrapper. This will keep the request
|
||||
context active during the generator.</p>
|
||||
<div class="highlight-python 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">stream_with_context</span><span class="p">,</span> <span class="n">request</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">markupsafe</span><span class="w"> </span><span class="kn">import</span> <span class="n">escape</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/stream'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">streamed_response</span><span class="p">():</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate</span><span class="p">():</span>
|
||||
<span class="k">yield</span> <span class="s1">'<p>Hello '</span>
|
||||
<span class="k">yield</span> <span class="n">escape</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="s1">'name'</span><span class="p">])</span>
|
||||
<span class="k">yield</span> <span class="s1">'!</p>'</span>
|
||||
<span class="k">return</span> <span class="n">stream_with_context</span><span class="p">(</span><span class="n">generate</span><span class="p">())</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It can also be used as a decorator.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@stream_with_context</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate</span><span class="p">():</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">generate</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <a class="reference internal" href="../api.html#flask.stream_template" title="flask.stream_template"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template()</span></code></a> and
|
||||
<a class="reference internal" href="../api.html#flask.stream_template_string" title="flask.stream_template_string"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template_string()</span></code></a> functions automatically
|
||||
use <a class="reference internal" href="../api.html#flask.stream_with_context" title="flask.stream_with_context"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_with_context()</span></code></a> if a request is active.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -77,20 +126,30 @@ requests to your SPA.</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="#">Streaming Contents</a><ul>
|
||||
<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li>
|
||||
<li><a class="reference internal" href="#streaming-from-templates">Streaming from Templates</a></li>
|
||||
<li><a class="reference internal" href="#streaming-with-context">Streaming with Context</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="subclassing.html" title="previous chapter">Subclassing Flask</a>
|
||||
<li>Next: <a href="../web-security.html" title="next chapter">Security Considerations</a></ul>
|
||||
<li>Previous: <a href="favicon.html" title="previous chapter">Adding a favicon</a>
|
||||
<li>Next: <a href="deferredcallbacks.html" title="next chapter">Deferred Request Callbacks</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -114,4 +173,4 @@ requests to your SPA.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>SQLAlchemy in Flask — Flask Documentation (3.2.x)</title>
|
||||
<title>Subclassing 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>
|
||||
|
|
@ -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="Uploading Files" href="fileuploads.html" />
|
||||
<link rel="prev" title="Using SQLite 3 with Flask" href="sqlite3.html" />
|
||||
<link rel="next" title="Single-Page Applications" href="singlepageapplications.html" />
|
||||
<link rel="prev" title="Background Tasks with Celery" href="celery.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,218 +28,37 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="fileuploads.html" title="Uploading Files"
|
||||
<a href="singlepageapplications.html" title="Single-Page Applications"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sqlite3.html" title="Using SQLite 3 with Flask"
|
||||
<a href="celery.html" title="Background Tasks with Celery"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">SQLAlchemy in Flask</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Subclassing Flask</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="sqlalchemy-in-flask">
|
||||
<h1>SQLAlchemy in Flask<a class="headerlink" href="#sqlalchemy-in-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>Many people prefer <a class="reference external" href="https://www.sqlalchemy.org/">SQLAlchemy</a> for database access. In this case it’s
|
||||
encouraged to use a package instead of a module for your flask application
|
||||
and drop the models into a separate module (<a class="reference internal" href="packages.html"><span class="doc">Large Applications as Packages</span></a>). While that
|
||||
is not necessary, it makes a lot of sense.</p>
|
||||
<p>There are four very common ways to use SQLAlchemy. I will outline each
|
||||
of them here:</p>
|
||||
<section id="flask-sqlalchemy-extension">
|
||||
<h2>Flask-SQLAlchemy Extension<a class="headerlink" href="#flask-sqlalchemy-extension" title="Link to this heading">¶</a></h2>
|
||||
<p>Because SQLAlchemy is a common database abstraction layer and object
|
||||
relational mapper that requires a little bit of configuration effort,
|
||||
there is a Flask extension that handles that for you. This is recommended
|
||||
if you want to get started quickly.</p>
|
||||
<p>You can download <a class="reference external" href="https://flask-sqlalchemy.palletsprojects.com/">Flask-SQLAlchemy</a> from <a class="reference external" href="https://pypi.org/project/Flask-SQLAlchemy/">PyPI</a>.</p>
|
||||
</section>
|
||||
<section id="declarative">
|
||||
<h2>Declarative<a class="headerlink" href="#declarative" title="Link to this heading">¶</a></h2>
|
||||
<p>The declarative extension in SQLAlchemy is the most recent method of using
|
||||
SQLAlchemy. It allows you to define tables and models in one go, similar
|
||||
to how Django works. In addition to the following text I recommend the
|
||||
official documentation on the <a class="reference external" href="https://docs.sqlalchemy.org/en/latest/orm/extensions/declarative/">declarative</a> extension.</p>
|
||||
<p>Here’s the example <code class="file docutils literal notranslate"><span class="pre">database.py</span></code> module for your application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_engine</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">scoped_session</span><span class="p">,</span> <span class="n">sessionmaker</span><span class="p">,</span> <span class="n">declarative_base</span>
|
||||
|
||||
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite:////tmp/test.db'</span><span class="p">)</span>
|
||||
<span class="n">db_session</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">autocommit</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">autoflush</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">))</span>
|
||||
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span>
|
||||
<span class="n">Base</span><span class="o">.</span><span class="n">query</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query_property</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">init_db</span><span class="p">():</span>
|
||||
<span class="c1"># import all modules here that might define models so that</span>
|
||||
<span class="c1"># they will be registered properly on the metadata. Otherwise</span>
|
||||
<span class="c1"># you will have to import them first before calling init_db()</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">yourapplication.models</span>
|
||||
<span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
|
||||
<section id="subclassing-flask">
|
||||
<h1>Subclassing Flask<a class="headerlink" href="#subclassing-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>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 is designed for subclassing.</p>
|
||||
<p>For example, you may want to override how request parameters are handled to preserve their order:</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="p">,</span> <span class="n">Request</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.datastructures</span><span class="w"> </span><span class="kn">import</span> <span class="n">ImmutableOrderedMultiDict</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyRequest</span><span class="p">(</span><span class="n">Request</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""Request subclass to override request parameter storage"""</span>
|
||||
<span class="n">parameter_storage_class</span> <span class="o">=</span> <span class="n">ImmutableOrderedMultiDict</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyFlask</span><span class="p">(</span><span class="n">Flask</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""Flask subclass using the custom request class"""</span>
|
||||
<span class="n">request_class</span> <span class="o">=</span> <span class="n">MyRequest</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To define your models, just subclass the <code class="code docutils literal notranslate"><span class="pre">Base</span></code> class that was created by
|
||||
the code above. If you are wondering why we don’t have to care about
|
||||
threads here (like we did in the SQLite3 example above with the
|
||||
<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> object): that’s because SQLAlchemy does that for us
|
||||
already with the <a class="reference external" href="https://docs.sqlalchemy.org/en/20/orm/contextual.html#sqlalchemy.orm.scoped_session" title="(in SQLAlchemy v2.0)"><code class="xref py py-class docutils literal notranslate"><span class="pre">scoped_session</span></code></a>.</p>
|
||||
<p>To use SQLAlchemy in a declarative way with your application, you just
|
||||
have to put the following code into your application module. Flask will
|
||||
automatically remove database sessions at the end of the request or
|
||||
when the application shuts down:</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.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_session</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_appcontext</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">shutdown_session</span><span class="p">(</span><span class="n">exception</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="n">db_session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here is an example model (put this into <code class="file docutils literal notranslate"><span class="pre">models.py</span></code>, e.g.):</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">Base</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">User</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
|
||||
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'users'</span>
|
||||
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="n">email</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</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">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s1">'<User </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">!r}</span><span class="s1">>'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To create the database you can use the <code class="code docutils literal notranslate"><span class="pre">init_db</span></code> function:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">init_db</span>
|
||||
<span class="gp">>>> </span><span class="n">init_db</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can insert entries into the database like this:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_session</span>
|
||||
<span class="gp">>>> </span><span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="s1">'admin'</span><span class="p">,</span> <span class="s1">'admin@localhost'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">u</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">db_session</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Querying is simple as well:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||||
<span class="go">[<User 'admin'>]</span>
|
||||
<span class="gp">>>> </span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s1">'admin'</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="go"><User 'admin'></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="manual-object-relational-mapping">
|
||||
<h2>Manual Object Relational Mapping<a class="headerlink" href="#manual-object-relational-mapping" title="Link to this heading">¶</a></h2>
|
||||
<p>Manual object relational mapping has a few upsides and a few downsides
|
||||
versus the declarative approach from above. The main difference is that
|
||||
you define tables and classes separately and map them together. It’s more
|
||||
flexible but a little more to type. In general it works like the
|
||||
declarative approach, so make sure to also split up your application into
|
||||
multiple modules in a package.</p>
|
||||
<p>Here is an example <code class="file docutils literal notranslate"><span class="pre">database.py</span></code> module for your application:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">scoped_session</span><span class="p">,</span> <span class="n">sessionmaker</span>
|
||||
|
||||
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite:////tmp/test.db'</span><span class="p">)</span>
|
||||
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span>
|
||||
<span class="n">db_session</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">autocommit</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">autoflush</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||||
<span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">))</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">init_db</span><span class="p">():</span>
|
||||
<span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As in the declarative approach, you need to close the session after
|
||||
each request or application context shutdown. Put this into your
|
||||
application module:</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.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_session</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_appcontext</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">shutdown_session</span><span class="p">(</span><span class="n">exception</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="n">db_session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here is an example table and model (put this into <code class="file docutils literal notranslate"><span class="pre">models.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">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">Table</span><span class="p">,</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy.orm</span><span class="w"> </span><span class="kn">import</span> <span class="n">mapper</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">yourapplication.database</span><span class="w"> </span><span class="kn">import</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">db_session</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">User</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="n">query</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query_property</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">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="sa">f</span><span class="s1">'<User </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">!r}</span><span class="s1">>'</span>
|
||||
|
||||
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span>
|
||||
<span class="n">Column</span><span class="p">(</span><span class="s1">'id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span>
|
||||
<span class="n">Column</span><span class="p">(</span><span class="s1">'name'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span>
|
||||
<span class="n">Column</span><span class="p">(</span><span class="s1">'email'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">mapper</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">users</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Querying and inserting works exactly the same as in the example above.</p>
|
||||
</section>
|
||||
<section id="sql-abstraction-layer">
|
||||
<h2>SQL Abstraction Layer<a class="headerlink" href="#sql-abstraction-layer" title="Link to this heading">¶</a></h2>
|
||||
<p>If you just want to use the database system (and SQL) abstraction layer
|
||||
you basically only need the engine:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span><span class="p">,</span> <span class="n">Table</span>
|
||||
|
||||
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite:////tmp/test.db'</span><span class="p">)</span>
|
||||
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Then you can either declare the tables in your code like in the examples
|
||||
above, or automatically load them:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">sqlalchemy</span><span class="w"> </span><span class="kn">import</span> <span class="n">Table</span>
|
||||
|
||||
<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">autoload</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To insert data you can use the <code class="code docutils literal notranslate"><span class="pre">insert</span></code> method. We have to get a
|
||||
connection first so that we can use a transaction:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">con</span> <span class="o">=</span> <span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
|
||||
<span class="gp">>>> </span><span class="n">con</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">insert</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s1">'admin@localhost'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>SQLAlchemy will automatically commit for us.</p>
|
||||
<p>To query your database, you use the engine directly or use a connection:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">users</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="go">(1, 'admin', 'admin@localhost')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>These results are also dict-like tuples:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span>
|
||||
<span class="go">'admin'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also pass strings of SQL statements to the
|
||||
<code class="xref py py-meth docutils literal notranslate"><span class="pre">execute()</span></code> method:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">engine</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s1">'select * from users where id = :1'</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||||
<span class="go">(1, 'admin', 'admin@localhost')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For more information about SQLAlchemy, head over to the
|
||||
<a class="reference external" href="https://www.sqlalchemy.org/">website</a>.</p>
|
||||
</section>
|
||||
<p>This is the recommended approach for overriding or augmenting Flask’s internal functionality.</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -250,31 +69,20 @@ connection first so that we can use a transaction:</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="#">SQLAlchemy in Flask</a><ul>
|
||||
<li><a class="reference internal" href="#flask-sqlalchemy-extension">Flask-SQLAlchemy Extension</a></li>
|
||||
<li><a class="reference internal" href="#declarative">Declarative</a></li>
|
||||
<li><a class="reference internal" href="#manual-object-relational-mapping">Manual Object Relational Mapping</a></li>
|
||||
<li><a class="reference internal" href="#sql-abstraction-layer">SQL Abstraction Layer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="sqlite3.html" title="previous chapter">Using SQLite 3 with Flask</a>
|
||||
<li>Next: <a href="fileuploads.html" title="next chapter">Uploading Files</a></ul>
|
||||
<li>Previous: <a href="celery.html" title="previous chapter">Background Tasks with Celery</a>
|
||||
<li>Next: <a href="singlepageapplications.html" title="next chapter">Single-Page Applications</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -298,4 +106,4 @@ connection first so that we can use a transaction:</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Using SQLite 3 with Flask — Flask Documentation (3.2.x)</title>
|
||||
<title>Template Inheritance — 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="SQLAlchemy in Flask" href="sqlalchemy.html" />
|
||||
<link rel="prev" title="Using URL Processors" href="urlprocessors.html" />
|
||||
<link rel="next" title="Message Flashing" href="flashing.html" />
|
||||
<link rel="prev" title="Form Validation with WTForms" href="wtforms.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,161 +28,80 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sqlalchemy.html" title="SQLAlchemy in Flask"
|
||||
<a href="flashing.html" title="Message Flashing"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="urlprocessors.html" title="Using URL Processors"
|
||||
<a href="wtforms.html" title="Form Validation with WTForms"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Using SQLite 3 with Flask</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Template Inheritance</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="using-sqlite-3-with-flask">
|
||||
<h1>Using SQLite 3 with Flask<a class="headerlink" href="#using-sqlite-3-with-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>In Flask you can easily implement the opening of database connections on
|
||||
demand and closing them when the context dies (usually at the end of the
|
||||
request).</p>
|
||||
<p>Here is a simple example of how you can use SQLite 3 with Flask:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">sqlite3</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">g</span>
|
||||
|
||||
<span class="n">DATABASE</span> <span class="o">=</span> <span class="s1">'/path/to/database.db'</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">get_db</span><span class="p">():</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s1">'_database'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">db</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">_database</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">DATABASE</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">db</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_appcontext</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">close_connection</span><span class="p">(</span><span class="n">exception</span><span class="p">):</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s1">'_database'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">db</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now, to use the database, the application must either have an active
|
||||
application context (which is always true if there is a request in flight)
|
||||
or create an application context itself. At that point the <code class="docutils literal notranslate"><span class="pre">get_db</span></code>
|
||||
function can be used to get the current database connection. Whenever the
|
||||
context is destroyed the database connection will be terminated.</p>
|
||||
<p>Example:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="n">cur</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>Please keep in mind that the teardown request and appcontext functions
|
||||
are always executed, even if a before-request handler failed or was
|
||||
never executed. Because of this we have to make sure here that the
|
||||
database is there before we close it.</p>
|
||||
</div>
|
||||
<section id="connect-on-demand">
|
||||
<h2>Connect on Demand<a class="headerlink" href="#connect-on-demand" title="Link to this heading">¶</a></h2>
|
||||
<p>The upside of this approach (connecting on first use) is that this will
|
||||
only open the connection if truly necessary. If you want to use this
|
||||
code outside a request context you can use it in a Python shell by opening
|
||||
the application context by hand:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">app_context</span><span class="p">():</span>
|
||||
<span class="c1"># now you can use get_db()</span>
|
||||
<section id="template-inheritance">
|
||||
<h1>Template Inheritance<a class="headerlink" href="#template-inheritance" title="Link to this heading">¶</a></h1>
|
||||
<p>The most powerful part of Jinja is template inheritance. Template inheritance
|
||||
allows you to build a base “skeleton” template that contains all the common
|
||||
elements of your site and defines <strong>blocks</strong> that child templates can override.</p>
|
||||
<p>Sounds complicated but is very basic. It’s easiest to understand it by starting
|
||||
with an example.</p>
|
||||
<section id="base-template">
|
||||
<h2>Base Template<a class="headerlink" href="#base-template" title="Link to this heading">¶</a></h2>
|
||||
<p>This template, which we’ll call <code class="file docutils literal notranslate"><span class="pre">layout.html</span></code>, defines a simple HTML skeleton
|
||||
document that you might use for a simple two-column page. It’s the job of
|
||||
“child” templates to fill the empty blocks with content:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp"><!doctype html></span>
|
||||
<span class="p"><</span><span class="nt">html</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">head</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'static'</span><span class="o">,</span> <span class="nv">filename</span><span class="o">=</span><span class="s1">'style.css'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">title</span><span class="p">></span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span> - My Webpage<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"content"</span><span class="p">></span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"footer"</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">footer</span> <span class="cp">%}</span>
|
||||
<span class="ni">&copy;</span> Copyright 2010 by <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://domain.invalid/"</span><span class="p">></span>you<span class="p"></</span><span class="nt">a</span><span class="p">></span>.
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In this example, the <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">%}</span></code> tags define four blocks that child templates
|
||||
can fill in. All the <code class="code docutils literal notranslate"><span class="pre">block</span></code> tag does is tell the template engine that a
|
||||
child template may override those portions of the template.</p>
|
||||
</section>
|
||||
<section id="easy-querying">
|
||||
<h2>Easy Querying<a class="headerlink" href="#easy-querying" title="Link to this heading">¶</a></h2>
|
||||
<p>Now in each request handling function you can access <code class="code docutils literal notranslate"><span class="pre">get_db()</span></code> to get the
|
||||
current open database connection. To simplify working with SQLite, a
|
||||
row factory function is useful. It is executed for every result returned
|
||||
from the database to convert the result. For instance, in order to get
|
||||
dictionaries instead of tuples, this could be inserted into the <code class="docutils literal notranslate"><span class="pre">get_db</span></code>
|
||||
function we created above:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">make_dicts</span><span class="p">(</span><span class="n">cursor</span><span class="p">,</span> <span class="n">row</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="nb">dict</span><span class="p">((</span><span class="n">cursor</span><span class="o">.</span><span class="n">description</span><span class="p">[</span><span class="n">idx</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">value</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">row</span><span class="p">))</span>
|
||||
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">make_dicts</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will make the sqlite3 module return dicts for this database connection, which are much nicer to deal with. Even more simply, we could place this in <code class="docutils literal notranslate"><span class="pre">get_db</span></code> instead:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">db</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This would use Row objects rather than dicts to return the results of queries. These are <code class="docutils literal notranslate"><span class="pre">namedtuple</span></code> s, so we can access them either by index or by key. For example, assuming we have a <code class="docutils literal notranslate"><span class="pre">sqlite3.Row</span></code> called <code class="docutils literal notranslate"><span class="pre">r</span></code> for the rows <code class="docutils literal notranslate"><span class="pre">id</span></code>, <code class="docutils literal notranslate"><span class="pre">FirstName</span></code>, <code class="docutils literal notranslate"><span class="pre">LastName</span></code>, and <code class="docutils literal notranslate"><span class="pre">MiddleInitial</span></code>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="c1"># You can get values based on the row's name</span>
|
||||
<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="s1">'FirstName'</span><span class="p">]</span>
|
||||
<span class="go">John</span>
|
||||
<span class="gp">>>> </span><span class="c1"># Or, you can get them based on index</span>
|
||||
<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="go">John</span>
|
||||
<span class="go"># Row objects are also iterable:</span>
|
||||
<span class="gp">>>> </span><span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">r</span><span class="p">:</span>
|
||||
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||||
<span class="go">1</span>
|
||||
<span class="go">John</span>
|
||||
<span class="go">Doe</span>
|
||||
<span class="go">M</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Additionally, it is a good idea to provide a query function that combines
|
||||
getting the cursor, executing and fetching the results:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">query_db</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(),</span> <span class="n">one</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
<span class="n">cur</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
|
||||
<span class="n">cur</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="p">(</span><span class="n">rv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">rv</span> <span class="k">else</span> <span class="kc">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">one</span> <span class="k">else</span> <span class="n">rv</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This handy little function, in combination with a row factory, makes
|
||||
working with the database much more pleasant than it is by just using the
|
||||
raw cursor and connection objects.</p>
|
||||
<p>Here is how you can use it:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">query_db</span><span class="p">(</span><span class="s1">'select * from users'</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">user</span><span class="p">[</span><span class="s1">'username'</span><span class="p">],</span> <span class="s1">'has the id'</span><span class="p">,</span> <span class="n">user</span><span class="p">[</span><span class="s1">'user_id'</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or if you just want a single result:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="n">query_db</span><span class="p">(</span><span class="s1">'select * from users where username = ?'</span><span class="p">,</span>
|
||||
<span class="p">[</span><span class="n">the_username</span><span class="p">],</span> <span class="n">one</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'No such user'</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">the_username</span><span class="p">,</span> <span class="s1">'has the id'</span><span class="p">,</span> <span class="n">user</span><span class="p">[</span><span class="s1">'user_id'</span><span class="p">])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To pass variable parts to the SQL statement, use a question mark in the
|
||||
statement and pass in the arguments as a list. Never directly add them to
|
||||
the SQL statement with string formatting because this makes it possible
|
||||
to attack the application using <a class="reference external" href="https://en.wikipedia.org/wiki/SQL_injection">SQL Injections</a>.</p>
|
||||
</section>
|
||||
<section id="initial-schemas">
|
||||
<h2>Initial Schemas<a class="headerlink" href="#initial-schemas" title="Link to this heading">¶</a></h2>
|
||||
<p>Relational databases need schemas, so applications often ship a
|
||||
<code class="code docutils literal notranslate"><span class="pre">schema.sql</span></code> file that creates the database. It’s a good idea to provide
|
||||
a function that creates the database based on that schema. This function
|
||||
can do that for you:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">init_db</span><span class="p">():</span>
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">app_context</span><span class="p">():</span>
|
||||
<span class="n">db</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span>
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">open_resource</span><span class="p">(</span><span class="s1">'schema.sql'</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span><span class="o">.</span><span class="n">executescript</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
|
||||
<span class="n">db</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can then create such a database from the Python shell:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </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">init_db</span>
|
||||
<span class="gp">>>> </span><span class="n">init_db</span><span class="p">()</span>
|
||||
<section id="child-template">
|
||||
<h2>Child Template<a class="headerlink" href="#child-template" title="Link to this heading">¶</a></h2>
|
||||
<p>A child template might look like this:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>Index<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">head</span> <span class="cp">%}</span>
|
||||
<span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span>
|
||||
<span class="p"><</span><span class="nt">style</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span><span class="p">></span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nc">important</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#336699</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p"></</span><span class="nt">style</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Index<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">"important"</span><span class="p">></span>
|
||||
Welcome on my awesome homepage.
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">%}</span></code> tag is the key here. It tells the template engine that
|
||||
this template “extends” another template. When the template system evaluates
|
||||
this template, first it locates the parent. The extends tag must be the
|
||||
first tag in the template. To render the contents of a block defined in
|
||||
the parent template, use <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">super()</span> <span class="pre">}}</span></code>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -194,19 +113,18 @@ can do that for you:</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="#">Using SQLite 3 with Flask</a><ul>
|
||||
<li><a class="reference internal" href="#connect-on-demand">Connect on Demand</a></li>
|
||||
<li><a class="reference internal" href="#easy-querying">Easy Querying</a></li>
|
||||
<li><a class="reference internal" href="#initial-schemas">Initial Schemas</a></li>
|
||||
<li><a class="reference internal" href="#">Template Inheritance</a><ul>
|
||||
<li><a class="reference internal" href="#base-template">Base Template</a></li>
|
||||
<li><a class="reference internal" href="#child-template">Child Template</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -216,8 +134,8 @@ can do that for you:</p>
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="urlprocessors.html" title="previous chapter">Using URL Processors</a>
|
||||
<li>Next: <a href="sqlalchemy.html" title="next chapter">SQLAlchemy in Flask</a></ul>
|
||||
<li>Previous: <a href="wtforms.html" title="previous chapter">Form Validation with WTForms</a>
|
||||
<li>Next: <a href="flashing.html" title="next chapter">Message Flashing</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -241,4 +159,4 @@ can do that for you:</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Streaming Contents — Flask Documentation (3.2.x)</title>
|
||||
<title>Using URL Processors — 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="Deferred Request Callbacks" href="deferredcallbacks.html" />
|
||||
<link rel="prev" title="Adding a favicon" href="favicon.html" />
|
||||
<link rel="next" title="Using SQLite 3 with Flask" href="sqlite3.html" />
|
||||
<link rel="prev" title="Application Dispatching" href="appdispatch.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,93 +28,145 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="deferredcallbacks.html" title="Deferred Request Callbacks"
|
||||
<a href="sqlite3.html" title="Using SQLite 3 with Flask"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="favicon.html" title="Adding a favicon"
|
||||
<a href="appdispatch.html" title="Application Dispatching"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Streaming Contents</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Using URL Processors</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="streaming-contents">
|
||||
<h1>Streaming Contents<a class="headerlink" href="#streaming-contents" title="Link to this heading">¶</a></h1>
|
||||
<p>Sometimes you want to send an enormous amount of data to the client, much
|
||||
more than you want to keep in memory. When you are generating the data on
|
||||
the fly though, how do you send that back to the client without the
|
||||
roundtrip to the filesystem?</p>
|
||||
<p>The answer is by using generators and direct responses.</p>
|
||||
<section id="basic-usage">
|
||||
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Link to this heading">¶</a></h2>
|
||||
<p>This is a basic view function that generates a lot of CSV data on the fly.
|
||||
The trick is to have an inner function that uses a generator to generate
|
||||
data and to then invoke that function and pass it to a response object:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/large.csv'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate_large_csv</span><span class="p">():</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate</span><span class="p">():</span>
|
||||
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">iter_all_rows</span><span class="p">():</span>
|
||||
<span class="k">yield</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="s1">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">)</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span>
|
||||
<span class="k">return</span> <span class="n">generate</span><span class="p">(),</span> <span class="p">{</span><span class="s2">"Content-Type"</span><span class="p">:</span> <span class="s2">"text/csv"</span><span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Each <code class="docutils literal notranslate"><span class="pre">yield</span></code> expression is directly sent to the browser. Note though
|
||||
that some WSGI middlewares might break streaming, so be careful there in
|
||||
debug environments with profilers and other things you might have enabled.</p>
|
||||
</section>
|
||||
<section id="streaming-from-templates">
|
||||
<h2>Streaming from Templates<a class="headerlink" href="#streaming-from-templates" title="Link to this heading">¶</a></h2>
|
||||
<p>The Jinja2 template engine supports rendering a template piece by
|
||||
piece, returning an iterator of strings. Flask provides the
|
||||
<a class="reference internal" href="../api.html#flask.stream_template" title="flask.stream_template"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template()</span></code></a> and <a class="reference internal" href="../api.html#flask.stream_template_string" title="flask.stream_template_string"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template_string()</span></code></a>
|
||||
functions to make this easier to use.</p>
|
||||
<div class="highlight-python 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">stream_template</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/timeline"</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">timeline</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="n">stream_template</span><span class="p">(</span><span class="s2">"timeline.html"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
<section id="using-url-processors">
|
||||
<h1>Using URL Processors<a class="headerlink" href="#using-url-processors" title="Link to this heading">¶</a></h1>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.7.</span></p>
|
||||
</div>
|
||||
<p>The parts yielded by the render stream tend to match statement blocks in
|
||||
the template.</p>
|
||||
</section>
|
||||
<section id="streaming-with-context">
|
||||
<h2>Streaming with Context<a class="headerlink" href="#streaming-with-context" title="Link to this heading">¶</a></h2>
|
||||
<p>The <a class="reference internal" href="../api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> will not be active while the generator is
|
||||
running, because the view has already returned at that point. If you try
|
||||
to access <code class="docutils literal notranslate"><span class="pre">request</span></code>, you’ll get a <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>.</p>
|
||||
<p>If your generator function relies on data in <code class="docutils literal notranslate"><span class="pre">request</span></code>, use the
|
||||
<a class="reference internal" href="../api.html#flask.stream_with_context" title="flask.stream_with_context"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_with_context()</span></code></a> wrapper. This will keep the request
|
||||
context active during the generator.</p>
|
||||
<div class="highlight-python 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">stream_with_context</span><span class="p">,</span> <span class="n">request</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">markupsafe</span><span class="w"> </span><span class="kn">import</span> <span class="n">escape</span>
|
||||
</details><p>Flask 0.7 introduces the concept of URL processors. The idea is that you
|
||||
might have a bunch of resources with common parts in the URL that you
|
||||
don’t always explicitly want to provide. For instance you might have a
|
||||
bunch of URLs that have the language code in it but you don’t want to have
|
||||
to handle it in every single function yourself.</p>
|
||||
<p>URL processors are especially helpful when combined with blueprints. We
|
||||
will handle both application specific URL processors here as well as
|
||||
blueprint specifics.</p>
|
||||
<section id="internationalized-application-urls">
|
||||
<h2>Internationalized Application URLs<a class="headerlink" href="#internationalized-application-urls" title="Link to this heading">¶</a></h2>
|
||||
<p>Consider an application 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="p">,</span> <span class="n">g</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/stream'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">streamed_response</span><span class="p">():</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate</span><span class="p">():</span>
|
||||
<span class="k">yield</span> <span class="s1">'<p>Hello '</span>
|
||||
<span class="k">yield</span> <span class="n">escape</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="s1">'name'</span><span class="p">])</span>
|
||||
<span class="k">yield</span> <span class="s1">'!</p>'</span>
|
||||
<span class="k">return</span> <span class="n">stream_with_context</span><span class="p">(</span><span class="n">generate</span><span class="p">())</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It can also be used as a decorator.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@stream_with_context</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">generate</span><span class="p">():</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">'/<lang_code>/'</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="n">lang_code</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">lang_code</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">generate</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">'/<lang_code>/about'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">about</span><span class="p">(</span><span class="n">lang_code</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">lang_code</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is an awful lot of repetition as you have to handle the language code
|
||||
setting on the <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> object yourself in every single function.
|
||||
Sure, a decorator could be used to simplify this, but if you want to
|
||||
generate URLs from one function to another you would have to still provide
|
||||
the language code explicitly which can be annoying.</p>
|
||||
<p>For the latter, this is where <a class="reference internal" href="../api.html#flask.Flask.url_defaults" title="flask.Flask.url_defaults"><code class="xref py py-func docutils literal notranslate"><span class="pre">url_defaults()</span></code></a> functions
|
||||
come in. They can automatically inject values into a call to
|
||||
<a class="reference internal" href="../api.html#flask.url_for" title="flask.url_for"><code class="xref py py-func docutils literal notranslate"><span class="pre">url_for()</span></code></a>. The code below checks if the
|
||||
language code is not yet in the dictionary of URL values and if the
|
||||
endpoint wants a value named <code class="docutils literal notranslate"><span class="pre">'lang_code'</span></code>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">url_defaults</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="s1">'lang_code'</span> <span class="ow">in</span> <span class="n">values</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
<span class="k">if</span> <span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">is_endpoint_expecting</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="s1">'lang_code'</span><span class="p">):</span>
|
||||
<span class="n">values</span><span class="p">[</span><span class="s1">'lang_code'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The method <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/routing/#werkzeug.routing.Map.is_endpoint_expecting" title="(in Werkzeug v3.1.x)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">is_endpoint_expecting()</span></code></a> of the URL
|
||||
map can be used to figure out if it would make sense to provide a language
|
||||
code for the given endpoint.</p>
|
||||
<p>The reverse of that function are
|
||||
<a class="reference internal" href="../api.html#flask.Flask.url_value_preprocessor" title="flask.Flask.url_value_preprocessor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">url_value_preprocessor()</span></code></a>s. They are executed right
|
||||
after the request was matched and can execute code based on the URL
|
||||
values. The idea is that they pull information out of the values
|
||||
dictionary and put it somewhere else:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">url_value_preprocessor</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That way you no longer have to do the <code class="code docutils literal notranslate"><span class="pre">lang_code</span></code> assignment to
|
||||
<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> in every function. You can further improve that by
|
||||
writing your own decorator that prefixes URLs with the language code, but
|
||||
the more beautiful solution is using a blueprint. Once the
|
||||
<code class="docutils literal notranslate"><span class="pre">'lang_code'</span></code> is popped from the values dictionary and it will no longer
|
||||
be forwarded to the view function reducing the code to 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="p">,</span> <span class="n">g</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">url_defaults</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="s1">'lang_code'</span> <span class="ow">in</span> <span class="n">values</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
<span class="k">if</span> <span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">is_endpoint_expecting</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="s1">'lang_code'</span><span class="p">):</span>
|
||||
<span class="n">values</span><span class="p">[</span><span class="s1">'lang_code'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">url_value_preprocessor</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">,</span> <span class="kc">None</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">'/<lang_code>/'</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="o">...</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/<lang_code>/about'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">about</span><span class="p">():</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="internationalized-blueprint-urls">
|
||||
<h2>Internationalized Blueprint URLs<a class="headerlink" href="#internationalized-blueprint-urls" title="Link to this heading">¶</a></h2>
|
||||
<p>Because blueprints can automatically prefix all URLs with a common string
|
||||
it’s easy to automatically do that for every function. Furthermore
|
||||
blueprints can have per-blueprint URL processors which removes a whole lot
|
||||
of logic from the <a class="reference internal" href="../api.html#flask.Flask.url_defaults" title="flask.Flask.url_defaults"><code class="xref py py-meth docutils literal notranslate"><span class="pre">url_defaults()</span></code></a> function because it no
|
||||
longer has to check if the URL is really interested in a <code class="docutils literal notranslate"><span class="pre">'lang_code'</span></code>
|
||||
parameter:</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">Blueprint</span><span class="p">,</span> <span class="n">g</span>
|
||||
|
||||
<span class="n">bp</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s1">'frontend'</span><span class="p">,</span> <span class="vm">__name__</span><span class="p">,</span> <span class="n">url_prefix</span><span class="o">=</span><span class="s1">'/<lang_code>'</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@bp</span><span class="o">.</span><span class="n">url_defaults</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">values</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">,</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@bp</span><span class="o">.</span><span class="n">url_value_preprocessor</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@bp</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="o">...</span>
|
||||
|
||||
<span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/about'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">about</span><span class="p">():</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <a class="reference internal" href="../api.html#flask.stream_template" title="flask.stream_template"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template()</span></code></a> and
|
||||
<a class="reference internal" href="../api.html#flask.stream_template_string" title="flask.stream_template_string"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_template_string()</span></code></a> functions automatically
|
||||
use <a class="reference internal" href="../api.html#flask.stream_with_context" title="flask.stream_with_context"><code class="xref py py-func docutils literal notranslate"><span class="pre">stream_with_context()</span></code></a> if a request is active.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -126,19 +178,18 @@ use <a class="reference internal" href="../api.html#flask.stream_with_context" t
|
|||
<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="#">Streaming Contents</a><ul>
|
||||
<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li>
|
||||
<li><a class="reference internal" href="#streaming-from-templates">Streaming from Templates</a></li>
|
||||
<li><a class="reference internal" href="#streaming-with-context">Streaming with Context</a></li>
|
||||
<li><a class="reference internal" href="#">Using URL Processors</a><ul>
|
||||
<li><a class="reference internal" href="#internationalized-application-urls">Internationalized Application URLs</a></li>
|
||||
<li><a class="reference internal" href="#internationalized-blueprint-urls">Internationalized Blueprint URLs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -148,8 +199,8 @@ use <a class="reference internal" href="../api.html#flask.stream_with_context" t
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="favicon.html" title="previous chapter">Adding a favicon</a>
|
||||
<li>Next: <a href="deferredcallbacks.html" title="next chapter">Deferred Request Callbacks</a></ul>
|
||||
<li>Previous: <a href="appdispatch.html" title="previous chapter">Application Dispatching</a>
|
||||
<li>Next: <a href="sqlite3.html" title="next chapter">Using SQLite 3 with Flask</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -173,4 +224,4 @@ use <a class="reference internal" href="../api.html#flask.stream_with_context" t
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Subclassing Flask — Flask Documentation (3.2.x)</title>
|
||||
<title>View Decorators — 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="Single-Page Applications" href="singlepageapplications.html" />
|
||||
<link rel="prev" title="Background Tasks with Celery" href="celery.html" />
|
||||
<link rel="next" title="Form Validation with WTForms" href="wtforms.html" />
|
||||
<link rel="prev" title="Caching" href="caching.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,37 +28,186 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="singlepageapplications.html" title="Single-Page Applications"
|
||||
<a href="wtforms.html" title="Form Validation with WTForms"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="celery.html" title="Background Tasks with Celery"
|
||||
<a href="caching.html" title="Caching"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Subclassing Flask</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">View Decorators</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="subclassing-flask">
|
||||
<h1>Subclassing Flask<a class="headerlink" href="#subclassing-flask" title="Link to this heading">¶</a></h1>
|
||||
<p>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 is designed for subclassing.</p>
|
||||
<p>For example, you may want to override how request parameters are handled to preserve their order:</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="p">,</span> <span class="n">Request</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">werkzeug.datastructures</span><span class="w"> </span><span class="kn">import</span> <span class="n">ImmutableOrderedMultiDict</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyRequest</span><span class="p">(</span><span class="n">Request</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""Request subclass to override request parameter storage"""</span>
|
||||
<span class="n">parameter_storage_class</span> <span class="o">=</span> <span class="n">ImmutableOrderedMultiDict</span>
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">MyFlask</span><span class="p">(</span><span class="n">Flask</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""Flask subclass using the custom request class"""</span>
|
||||
<span class="n">request_class</span> <span class="o">=</span> <span class="n">MyRequest</span>
|
||||
|
||||
<section id="view-decorators">
|
||||
<h1>View Decorators<a class="headerlink" href="#view-decorators" title="Link to this heading">¶</a></h1>
|
||||
<p>Python has a really interesting feature called function decorators. This
|
||||
allows some really neat things for web applications. Because each view in
|
||||
Flask is a function, decorators can be used to inject additional
|
||||
functionality to one or more functions. The <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 is the one you probably used already. But there are use cases
|
||||
for implementing your own decorator. For instance, imagine you have a
|
||||
view that should only be used by people that are logged in. If a user
|
||||
goes to the site and is not logged in, they should be redirected to the
|
||||
login page. This is a good example of a use case where a decorator is an
|
||||
excellent solution.</p>
|
||||
<section id="login-required-decorator">
|
||||
<h2>Login Required Decorator<a class="headerlink" href="#login-required-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>So let’s implement such a decorator. A decorator is a function that
|
||||
wraps and replaces another function. Since the original function is
|
||||
replaced, you need to remember to copy the original function’s information
|
||||
to the new function. Use <a class="reference external" href="https://docs.python.org/3/library/functools.html#functools.wraps" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.wraps()</span></code></a> to handle this for you.</p>
|
||||
<p>This example assumes that the login page is called <code class="docutils literal notranslate"><span class="pre">'login'</span></code> and that
|
||||
the current user is stored in <code class="docutils literal notranslate"><span class="pre">g.user</span></code> and is <code class="docutils literal notranslate"><span class="pre">None</span></code> if there is no-one
|
||||
logged in.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">wraps</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">g</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">login_required</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
|
||||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorated_function</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">if</span> <span class="n">g</span><span class="o">.</span><span class="n">user</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'login'</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">f</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="n">decorated_function</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is the recommended approach for overriding or augmenting Flask’s internal functionality.</p>
|
||||
<p>To use the decorator, apply it as innermost decorator to a view function.
|
||||
When applying further decorators, always remember
|
||||
that the <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 is the outermost.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/secret_page'</span><span class="p">)</span>
|
||||
<span class="nd">@login_required</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">secret_page</span><span class="p">():</span>
|
||||
<span class="k">pass</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">next</span></code> value will exist in <code class="docutils literal notranslate"><span class="pre">request.args</span></code> after a <code class="docutils literal notranslate"><span class="pre">GET</span></code> request for
|
||||
the login page. You’ll have to pass it along when sending the <code class="docutils literal notranslate"><span class="pre">POST</span></code> request
|
||||
from the login form. You can do this with a hidden input tag, then retrieve it
|
||||
from <code class="docutils literal notranslate"><span class="pre">request.form</span></code> when logging the user in.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="nb">input</span> <span class="nb">type</span><span class="o">=</span><span class="s2">"hidden"</span> <span class="n">value</span><span class="o">=</span><span class="s2">"{{ request.args.get('next', '') }}"</span><span class="o">/></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="caching-decorator">
|
||||
<h2>Caching Decorator<a class="headerlink" href="#caching-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>Imagine you have a view function that does an expensive calculation and
|
||||
because of that you would like to cache the generated results for a
|
||||
certain amount of time. A decorator would be nice for that. We’re
|
||||
assuming you have set up a cache like mentioned in <a class="reference internal" href="caching.html"><span class="doc">Caching</span></a>.</p>
|
||||
<p>Here is an example cache function. It generates the cache key from a
|
||||
specific prefix (actually a format string) and the current path of the
|
||||
request. Notice that we are using a function that first creates the
|
||||
decorator that then decorates the function. Sounds awful? Unfortunately
|
||||
it is a little bit more complex, but the code should still be
|
||||
straightforward to read.</p>
|
||||
<p>The decorated function will then work as follows</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>get the unique cache key for the current request based on the current
|
||||
path.</p></li>
|
||||
<li><p>get the value for that key from the cache. If the cache returned
|
||||
something we will return that value.</p></li>
|
||||
<li><p>otherwise the original function is called and the return value is
|
||||
stored in the cache for the timeout provided (by default 5 minutes).</p></li>
|
||||
</ol>
|
||||
<p>Here the 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">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">wraps</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">request</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">cached</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">60</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s1">'view/</span><span class="si">{}</span><span class="s1">'</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
|
||||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorated_function</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="n">cache_key</span> <span class="o">=</span> <span class="n">key</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="p">)</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="n">cache</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cache_key</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">rv</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
<span class="n">rv</span> <span class="o">=</span> <span class="n">f</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="n">cache</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">cache_key</span><span class="p">,</span> <span class="n">rv</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">rv</span>
|
||||
<span class="k">return</span> <span class="n">decorated_function</span>
|
||||
<span class="k">return</span> <span class="n">decorator</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Notice that this assumes an instantiated <code class="docutils literal notranslate"><span class="pre">cache</span></code> object is available, see
|
||||
<a class="reference internal" href="caching.html"><span class="doc">Caching</span></a>.</p>
|
||||
</section>
|
||||
<section id="templating-decorator">
|
||||
<h2>Templating Decorator<a class="headerlink" href="#templating-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>A common pattern invented by the TurboGears guys a while back is a
|
||||
templating decorator. The idea of that decorator is that you return a
|
||||
dictionary with the values passed to the template from the view function
|
||||
and the template is automatically rendered. With that, the following
|
||||
three examples do exactly the same:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="n">render_template</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">42</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="nd">@templated</span><span class="p">(</span><span class="s1">'index.html'</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="nb">dict</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">42</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="nd">@templated</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="nb">dict</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As you can see, if no template name is provided it will use the endpoint
|
||||
of the URL map with dots converted to slashes + <code class="docutils literal notranslate"><span class="pre">'.html'</span></code>. Otherwise
|
||||
the provided template name is used. When the decorated function returns,
|
||||
the dictionary returned is passed to the template rendering function. If
|
||||
<code class="docutils literal notranslate"><span class="pre">None</span></code> is returned, an empty dictionary is assumed, if something else than
|
||||
a dictionary is returned we return it from the function unchanged. That
|
||||
way you can still use the redirect function or return simple strings.</p>
|
||||
<p>Here is the code for that decorator:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">wraps</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">request</span><span class="p">,</span> <span class="n">render_template</span>
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">templated</span><span class="p">(</span><span class="n">template</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
|
||||
<span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">decorated_function</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="n">template_name</span> <span class="o">=</span> <span class="n">template</span>
|
||||
<span class="k">if</span> <span class="n">template_name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">template_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">request</span><span class="o">.</span><span class="n">endpoint</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'.'</span><span class="p">,</span><span class="w"> </span><span class="s1">'/'</span><span class="p">)</span><span class="si">}</span><span class="s2">.html"</span>
|
||||
<span class="n">ctx</span> <span class="o">=</span> <span class="n">f</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">if</span> <span class="n">ctx</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">ctx</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="k">elif</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">ctx</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="n">template_name</span><span class="p">,</span> <span class="o">**</span><span class="n">ctx</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">decorated_function</span>
|
||||
<span class="k">return</span> <span class="n">decorator</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="endpoint-decorator">
|
||||
<h2>Endpoint Decorator<a class="headerlink" href="#endpoint-decorator" title="Link to this heading">¶</a></h2>
|
||||
<p>When you want to use the werkzeug routing system for more flexibility you
|
||||
need to map the endpoint as defined in the <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/routing/#werkzeug.routing.Rule" title="(in Werkzeug v3.1.x)"><code class="xref py py-class docutils literal notranslate"><span class="pre">Rule</span></code></a>
|
||||
to a view function. This is possible with this decorator. For example:</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">werkzeug.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Rule</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">url_map</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Rule</span><span class="p">(</span><span class="s1">'/'</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="s1">'index'</span><span class="p">))</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">endpoint</span><span class="p">(</span><span class="s1">'index'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">my_index</span><span class="p">():</span>
|
||||
<span class="k">return</span> <span class="s2">"Hello world"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -69,20 +218,31 @@
|
|||
<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="#">View Decorators</a><ul>
|
||||
<li><a class="reference internal" href="#login-required-decorator">Login Required Decorator</a></li>
|
||||
<li><a class="reference internal" href="#caching-decorator">Caching Decorator</a></li>
|
||||
<li><a class="reference internal" href="#templating-decorator">Templating Decorator</a></li>
|
||||
<li><a class="reference internal" href="#endpoint-decorator">Endpoint Decorator</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="celery.html" title="previous chapter">Background Tasks with Celery</a>
|
||||
<li>Next: <a href="singlepageapplications.html" title="next chapter">Single-Page Applications</a></ul>
|
||||
<li>Previous: <a href="caching.html" title="previous chapter">Caching</a>
|
||||
<li>Next: <a href="wtforms.html" title="next chapter">Form Validation with WTForms</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -106,4 +266,4 @@
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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>Template Inheritance — Flask Documentation (3.2.x)</title>
|
||||
<title>Form Validation with WTForms — 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="Message Flashing" href="flashing.html" />
|
||||
<link rel="prev" title="Form Validation with WTForms" href="wtforms.html" />
|
||||
<link rel="next" title="Template Inheritance" href="templateinheritance.html" />
|
||||
<link rel="prev" title="View Decorators" href="viewdecorators.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="Related">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -28,80 +28,131 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="flashing.html" title="Message Flashing"
|
||||
<a href="templateinheritance.html" title="Template Inheritance"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="wtforms.html" title="Form Validation with WTForms"
|
||||
<a href="viewdecorators.html" title="View Decorators"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Template Inheritance</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">Form Validation with WTForms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="template-inheritance">
|
||||
<h1>Template Inheritance<a class="headerlink" href="#template-inheritance" title="Link to this heading">¶</a></h1>
|
||||
<p>The most powerful part of Jinja is template inheritance. Template inheritance
|
||||
allows you to build a base “skeleton” template that contains all the common
|
||||
elements of your site and defines <strong>blocks</strong> that child templates can override.</p>
|
||||
<p>Sounds complicated but is very basic. It’s easiest to understand it by starting
|
||||
with an example.</p>
|
||||
<section id="base-template">
|
||||
<h2>Base Template<a class="headerlink" href="#base-template" title="Link to this heading">¶</a></h2>
|
||||
<p>This template, which we’ll call <code class="file docutils literal notranslate"><span class="pre">layout.html</span></code>, defines a simple HTML skeleton
|
||||
document that you might use for a simple two-column page. It’s the job of
|
||||
“child” templates to fill the empty blocks with content:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp"><!doctype html></span>
|
||||
<span class="p"><</span><span class="nt">html</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">head</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'static'</span><span class="o">,</span> <span class="nv">filename</span><span class="o">=</span><span class="s1">'style.css'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">title</span><span class="p">></span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span> - My Webpage<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"content"</span><span class="p">></span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"footer"</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">footer</span> <span class="cp">%}</span>
|
||||
<span class="ni">&copy;</span> Copyright 2010 by <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://domain.invalid/"</span><span class="p">></span>you<span class="p"></</span><span class="nt">a</span><span class="p">></span>.
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
|
||||
|
||||
<section id="form-validation-with-wtforms">
|
||||
<h1>Form Validation with WTForms<a class="headerlink" href="#form-validation-with-wtforms" title="Link to this heading">¶</a></h1>
|
||||
<p>When you have to work with form data submitted by a browser view, code
|
||||
quickly becomes very hard to read. There are libraries out there designed
|
||||
to make this process easier to manage. One of them is <a class="reference external" href="https://wtforms.readthedocs.io/">WTForms</a> which we
|
||||
will handle here. If you find yourself in the situation of having many
|
||||
forms, you might want to give it a try.</p>
|
||||
<p>When you are working with WTForms you have to define your forms as classes
|
||||
first. I recommend breaking up the application into multiple modules
|
||||
(<a class="reference internal" href="packages.html"><span class="doc">Large Applications as Packages</span></a>) for that and adding a separate module for the
|
||||
forms.</p>
|
||||
<div class="admonition-getting-the-most-out-of-wtforms-with-an-extension admonition">
|
||||
<p class="admonition-title">Getting the most out of WTForms with an Extension</p>
|
||||
<p>The <a class="reference external" href="https://flask-wtf.readthedocs.io/">Flask-WTF</a> extension expands on this pattern and adds a
|
||||
few little helpers that make working with forms and Flask more
|
||||
fun. You can get it from <a class="reference external" href="https://pypi.org/project/Flask-WTF/">PyPI</a>.</p>
|
||||
</div>
|
||||
<section id="the-forms">
|
||||
<h2>The Forms<a class="headerlink" href="#the-forms" title="Link to this heading">¶</a></h2>
|
||||
<p>This is an example form for a typical registration page:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">wtforms</span><span class="w"> </span><span class="kn">import</span> <span class="n">Form</span><span class="p">,</span> <span class="n">BooleanField</span><span class="p">,</span> <span class="n">StringField</span><span class="p">,</span> <span class="n">PasswordField</span><span class="p">,</span> <span class="n">validators</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">RegistrationForm</span><span class="p">(</span><span class="n">Form</span><span class="p">):</span>
|
||||
<span class="n">username</span> <span class="o">=</span> <span class="n">StringField</span><span class="p">(</span><span class="s1">'Username'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Length</span><span class="p">(</span><span class="nb">min</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">25</span><span class="p">)])</span>
|
||||
<span class="n">email</span> <span class="o">=</span> <span class="n">StringField</span><span class="p">(</span><span class="s1">'Email Address'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Length</span><span class="p">(</span><span class="nb">min</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">35</span><span class="p">)])</span>
|
||||
<span class="n">password</span> <span class="o">=</span> <span class="n">PasswordField</span><span class="p">(</span><span class="s1">'New Password'</span><span class="p">,</span> <span class="p">[</span>
|
||||
<span class="n">validators</span><span class="o">.</span><span class="n">DataRequired</span><span class="p">(),</span>
|
||||
<span class="n">validators</span><span class="o">.</span><span class="n">EqualTo</span><span class="p">(</span><span class="s1">'confirm'</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s1">'Passwords must match'</span><span class="p">)</span>
|
||||
<span class="p">])</span>
|
||||
<span class="n">confirm</span> <span class="o">=</span> <span class="n">PasswordField</span><span class="p">(</span><span class="s1">'Repeat Password'</span><span class="p">)</span>
|
||||
<span class="n">accept_tos</span> <span class="o">=</span> <span class="n">BooleanField</span><span class="p">(</span><span class="s1">'I accept the TOS'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">DataRequired</span><span class="p">()])</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In this example, the <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">%}</span></code> tags define four blocks that child templates
|
||||
can fill in. All the <code class="code docutils literal notranslate"><span class="pre">block</span></code> tag does is tell the template engine that a
|
||||
child template may override those portions of the template.</p>
|
||||
</section>
|
||||
<section id="child-template">
|
||||
<h2>Child Template<a class="headerlink" href="#child-template" title="Link to this heading">¶</a></h2>
|
||||
<p>A child template might look like this:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>Index<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">head</span> <span class="cp">%}</span>
|
||||
<span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span>
|
||||
<span class="p"><</span><span class="nt">style</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span><span class="p">></span>
|
||||
<span class="w"> </span><span class="p">.</span><span class="nc">important</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#336699</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
|
||||
<span class="w"> </span><span class="p"></</span><span class="nt">style</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Index<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">"important"</span><span class="p">></span>
|
||||
Welcome on my awesome homepage.
|
||||
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
|
||||
<section id="in-the-view">
|
||||
<h2>In the View<a class="headerlink" href="#in-the-view" title="Link to this heading">¶</a></h2>
|
||||
<p>In the view function, the usage of this form looks like this:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/register'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">register</span><span class="p">():</span>
|
||||
<span class="n">form</span> <span class="o">=</span> <span class="n">RegistrationForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span> <span class="ow">and</span> <span class="n">form</span><span class="o">.</span><span class="n">validate</span><span class="p">():</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="n">form</span><span class="o">.</span><span class="n">email</span><span class="o">.</span><span class="n">data</span><span class="p">,</span>
|
||||
<span class="n">form</span><span class="o">.</span><span class="n">password</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>
|
||||
<span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'Thanks for registering'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'login'</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">'register.html'</span><span class="p">,</span> <span class="n">form</span><span class="o">=</span><span class="n">form</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">%}</span></code> tag is the key here. It tells the template engine that
|
||||
this template “extends” another template. When the template system evaluates
|
||||
this template, first it locates the parent. The extends tag must be the
|
||||
first tag in the template. To render the contents of a block defined in
|
||||
the parent template, use <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">super()</span> <span class="pre">}}</span></code>.</p>
|
||||
<p>Notice we’re implying that the view is using SQLAlchemy here
|
||||
(<a class="reference internal" href="sqlalchemy.html"><span class="doc">SQLAlchemy in Flask</span></a>), but that’s not a requirement, of course. Adapt
|
||||
the code as necessary.</p>
|
||||
<p>Things to remember:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>create the form from the request <code class="xref py py-attr docutils literal notranslate"><span class="pre">form</span></code> value if
|
||||
the data is submitted via the HTTP <code class="docutils literal notranslate"><span class="pre">POST</span></code> method and
|
||||
<code class="xref py py-attr docutils literal notranslate"><span class="pre">args</span></code> if the data is submitted as <code class="docutils literal notranslate"><span class="pre">GET</span></code>.</p></li>
|
||||
<li><p>to validate the data, call the <code class="xref py py-func docutils literal notranslate"><span class="pre">validate()</span></code>
|
||||
method, which will return <code class="docutils literal notranslate"><span class="pre">True</span></code> if the data validates, <code class="docutils literal notranslate"><span class="pre">False</span></code>
|
||||
otherwise.</p></li>
|
||||
<li><p>to access individual values from the form, access <code class="code docutils literal notranslate"><span class="pre">form.<NAME>.data</span></code>.</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
<section id="forms-in-templates">
|
||||
<h2>Forms in Templates<a class="headerlink" href="#forms-in-templates" title="Link to this heading">¶</a></h2>
|
||||
<p>Now to the template side. When you pass the form to the templates, you can
|
||||
easily render them there. Look at the following example template to see
|
||||
how easy this is. WTForms does half the form generation for us already.
|
||||
To make it even nicer, we can write a macro that renders a field with
|
||||
label and a list of errors if there are any.</p>
|
||||
<p>Here’s an example <code class="file docutils literal notranslate"><span class="pre">_formhelpers.html</span></code> template with such a macro:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">macro</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">field</span><span class="o">)</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">dt</span><span class="p">></span><span class="cp">{{</span> <span class="nv">field.label</span> <span class="cp">}}</span>
|
||||
<span class="p"><</span><span class="nt">dd</span><span class="p">></span><span class="cp">{{</span> <span class="nv">field</span><span class="o">(**</span><span class="nv">kwargs</span><span class="o">)|</span><span class="nf">safe</span> <span class="cp">}}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">field.errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">errors</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">error</span> <span class="k">in</span> <span class="nv">field.errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">error</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">dd</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endmacro</span> <span class="cp">%}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This macro accepts a couple of keyword arguments that are forwarded to
|
||||
WTForm’s field function, which renders the field for us. The keyword
|
||||
arguments will be inserted as HTML attributes. So, for example, you can
|
||||
call <code class="docutils literal notranslate"><span class="pre">render_field(form.username,</span> <span class="pre">class='username')</span></code> to add a class to
|
||||
the input element. Note that WTForms returns standard Python strings,
|
||||
so we have to tell Jinja2 that this data is already HTML-escaped with
|
||||
the <code class="docutils literal notranslate"><span class="pre">|safe</span></code> filter.</p>
|
||||
<p>Here is the <code class="file docutils literal notranslate"><span class="pre">register.html</span></code> template for the function we used above, which
|
||||
takes advantage of the <code class="file docutils literal notranslate"><span class="pre">_formhelpers.html</span></code> template:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">from</span> <span class="s2">"_formhelpers.html"</span> <span class="k">import</span> <span class="nv">render_field</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">post</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.username</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.email</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.password</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.confirm</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.accept_tos</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="p"></</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">submit</span> <span class="na">value</span><span class="o">=</span><span class="s">Register</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For more information about WTForms, head over to the <a class="reference external" href="https://wtforms.readthedocs.io/">WTForms
|
||||
website</a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -113,18 +164,19 @@ the parent template, use <code class="docutils literal notranslate"><span class=
|
|||
<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="#">Template Inheritance</a><ul>
|
||||
<li><a class="reference internal" href="#base-template">Base Template</a></li>
|
||||
<li><a class="reference internal" href="#child-template">Child Template</a></li>
|
||||
<li><a class="reference internal" href="#">Form Validation with WTForms</a><ul>
|
||||
<li><a class="reference internal" href="#the-forms">The Forms</a></li>
|
||||
<li><a class="reference internal" href="#in-the-view">In the View</a></li>
|
||||
<li><a class="reference internal" href="#forms-in-templates">Forms in Templates</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -134,8 +186,8 @@ the parent template, use <code class="docutils literal notranslate"><span class=
|
|||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="wtforms.html" title="previous chapter">Form Validation with WTForms</a>
|
||||
<li>Next: <a href="flashing.html" title="next chapter">Message Flashing</a></ul>
|
||||
<li>Previous: <a href="viewdecorators.html" title="previous chapter">View Decorators</a>
|
||||
<li>Next: <a href="templateinheritance.html" title="next chapter">Template Inheritance</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -159,4 +211,4 @@ the parent template, use <code class="docutils literal notranslate"><span class=
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,174 +1,71 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" data-content_root="../">
|
||||
<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>Using URL Processors — 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="Using SQLite 3 with Flask" href="sqlite3.html" />
|
||||
<link rel="prev" title="Application Dispatching" href="appdispatch.html" />
|
||||
<title>Python Module Index — 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" />
|
||||
|
||||
|
||||
|
||||
</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"
|
||||
<a href="genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
<a href="#" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sqlite3.html" title="Using SQLite 3 with Flask"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="appdispatch.html" title="Application Dispatching"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Using URL Processors</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="">Python Module Index</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="using-url-processors">
|
||||
<h1>Using URL Processors<a class="headerlink" href="#using-url-processors" title="Link to this heading">¶</a></h1>
|
||||
<details class="changelog">
|
||||
<summary>Changelog</summary><div class="versionadded">
|
||||
<p><span class="versionmodified added">Added in version 0.7.</span></p>
|
||||
</div>
|
||||
</details><p>Flask 0.7 introduces the concept of URL processors. The idea is that you
|
||||
might have a bunch of resources with common parts in the URL that you
|
||||
don’t always explicitly want to provide. For instance you might have a
|
||||
bunch of URLs that have the language code in it but you don’t want to have
|
||||
to handle it in every single function yourself.</p>
|
||||
<p>URL processors are especially helpful when combined with blueprints. We
|
||||
will handle both application specific URL processors here as well as
|
||||
blueprint specifics.</p>
|
||||
<section id="internationalized-application-urls">
|
||||
<h2>Internationalized Application URLs<a class="headerlink" href="#internationalized-application-urls" title="Link to this heading">¶</a></h2>
|
||||
<p>Consider an application 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="p">,</span> <span class="n">g</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">'/<lang_code>/'</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="n">lang_code</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">lang_code</span>
|
||||
<span class="o">...</span>
|
||||
<h1>Python Module Index</h1>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/<lang_code>/about'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">about</span><span class="p">(</span><span class="n">lang_code</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">lang_code</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is an awful lot of repetition as you have to handle the language code
|
||||
setting on the <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> object yourself in every single function.
|
||||
Sure, a decorator could be used to simplify this, but if you want to
|
||||
generate URLs from one function to another you would have to still provide
|
||||
the language code explicitly which can be annoying.</p>
|
||||
<p>For the latter, this is where <a class="reference internal" href="../api.html#flask.Flask.url_defaults" title="flask.Flask.url_defaults"><code class="xref py py-func docutils literal notranslate"><span class="pre">url_defaults()</span></code></a> functions
|
||||
come in. They can automatically inject values into a call to
|
||||
<a class="reference internal" href="../api.html#flask.url_for" title="flask.url_for"><code class="xref py py-func docutils literal notranslate"><span class="pre">url_for()</span></code></a>. The code below checks if the
|
||||
language code is not yet in the dictionary of URL values and if the
|
||||
endpoint wants a value named <code class="docutils literal notranslate"><span class="pre">'lang_code'</span></code>:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">url_defaults</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="s1">'lang_code'</span> <span class="ow">in</span> <span class="n">values</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
<span class="k">if</span> <span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">is_endpoint_expecting</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="s1">'lang_code'</span><span class="p">):</span>
|
||||
<span class="n">values</span><span class="p">[</span><span class="s1">'lang_code'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The method <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/routing/#werkzeug.routing.Map.is_endpoint_expecting" title="(in Werkzeug v3.1.x)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">is_endpoint_expecting()</span></code></a> of the URL
|
||||
map can be used to figure out if it would make sense to provide a language
|
||||
code for the given endpoint.</p>
|
||||
<p>The reverse of that function are
|
||||
<a class="reference internal" href="../api.html#flask.Flask.url_value_preprocessor" title="flask.Flask.url_value_preprocessor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">url_value_preprocessor()</span></code></a>s. They are executed right
|
||||
after the request was matched and can execute code based on the URL
|
||||
values. The idea is that they pull information out of the values
|
||||
dictionary and put it somewhere else:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">url_value_preprocessor</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That way you no longer have to do the <code class="code docutils literal notranslate"><span class="pre">lang_code</span></code> assignment to
|
||||
<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> in every function. You can further improve that by
|
||||
writing your own decorator that prefixes URLs with the language code, but
|
||||
the more beautiful solution is using a blueprint. Once the
|
||||
<code class="docutils literal notranslate"><span class="pre">'lang_code'</span></code> is popped from the values dictionary and it will no longer
|
||||
be forwarded to the view function reducing the code to 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="p">,</span> <span class="n">g</span>
|
||||
<div class="modindex-jumpbox">
|
||||
<a href="#cap-f"><strong>f</strong></a>
|
||||
</div>
|
||||
|
||||
<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">url_defaults</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="s1">'lang_code'</span> <span class="ow">in</span> <span class="n">values</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
<span class="k">if</span> <span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">is_endpoint_expecting</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="s1">'lang_code'</span><span class="p">):</span>
|
||||
<span class="n">values</span><span class="p">[</span><span class="s1">'lang_code'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">url_value_preprocessor</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">,</span> <span class="kc">None</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">'/<lang_code>/'</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="o">...</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/<lang_code>/about'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">about</span><span class="p">():</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="internationalized-blueprint-urls">
|
||||
<h2>Internationalized Blueprint URLs<a class="headerlink" href="#internationalized-blueprint-urls" title="Link to this heading">¶</a></h2>
|
||||
<p>Because blueprints can automatically prefix all URLs with a common string
|
||||
it’s easy to automatically do that for every function. Furthermore
|
||||
blueprints can have per-blueprint URL processors which removes a whole lot
|
||||
of logic from the <a class="reference internal" href="../api.html#flask.Flask.url_defaults" title="flask.Flask.url_defaults"><code class="xref py py-meth docutils literal notranslate"><span class="pre">url_defaults()</span></code></a> function because it no
|
||||
longer has to check if the URL is really interested in a <code class="docutils literal notranslate"><span class="pre">'lang_code'</span></code>
|
||||
parameter:</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">Blueprint</span><span class="p">,</span> <span class="n">g</span>
|
||||
|
||||
<span class="n">bp</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s1">'frontend'</span><span class="p">,</span> <span class="vm">__name__</span><span class="p">,</span> <span class="n">url_prefix</span><span class="o">=</span><span class="s1">'/<lang_code>'</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@bp</span><span class="o">.</span><span class="n">url_defaults</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">values</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">,</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@bp</span><span class="o">.</span><span class="n">url_value_preprocessor</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">'lang_code'</span><span class="p">)</span>
|
||||
|
||||
<span class="nd">@bp</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="o">...</span>
|
||||
|
||||
<span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/about'</span><span class="p">)</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">about</span><span class="p">():</span>
|
||||
<span class="o">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<table class="indextable modindextable">
|
||||
<tr class="pcap"><td></td><td> </td><td></td></tr>
|
||||
<tr class="cap" id="cap-f"><td></td><td>
|
||||
<strong>f</strong></td><td></td></tr>
|
||||
<tr>
|
||||
<td><img src="_static/minus.png" class="toggler"
|
||||
id="toggle-1" style="display: none" alt="-" /></td>
|
||||
<td>
|
||||
<a href="api.html#module-flask"><code class="xref">flask</code></a></td><td>
|
||||
<em></em></td></tr>
|
||||
<tr class="cg-1">
|
||||
<td></td>
|
||||
<td>   
|
||||
<a href="api.html#module-flask.json"><code class="xref">flask.json</code></a></td><td>
|
||||
<em></em></td></tr>
|
||||
<tr class="cg-1">
|
||||
<td></td>
|
||||
<td>   
|
||||
<a href="api.html#module-flask.json.tag"><code class="xref">flask.json.tag</code></a></td><td>
|
||||
<em></em></td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="clearer"></div>
|
||||
|
|
@ -178,37 +75,22 @@ parameter:</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="#">Using URL Processors</a><ul>
|
||||
<li><a class="reference internal" href="#internationalized-application-urls">Internationalized Application URLs</a></li>
|
||||
<li><a class="reference internal" href="#internationalized-blueprint-urls">Internationalized Blueprint URLs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="logo"><a href="index.html">
|
||||
<img class="logo" src="_static/flask-vertical.png" alt="Logo of Flask"/>
|
||||
</a></p>
|
||||
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="appdispatch.html" title="previous chapter">Application Dispatching</a>
|
||||
<li>Next: <a href="sqlite3.html" title="next chapter">Using SQLite 3 with Flask</a></ul>
|
||||
</li>
|
||||
</ul>
|
||||
<li><a href="index.html">Overview</a>
|
||||
|
||||
</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">
|
||||
<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>
|
||||
|
|
@ -224,4 +106,4 @@ parameter:</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,158 +1,252 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" data-content_root="../">
|
||||
<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>Form Validation with WTForms — 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="Template Inheritance" href="templateinheritance.html" />
|
||||
<link rel="prev" title="View Decorators" href="viewdecorators.html" />
|
||||
<title>The Request Context — 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="Modular Applications with Blueprints" href="blueprints.html" />
|
||||
<link rel="prev" title="The Application Context" href="appcontext.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"
|
||||
<a href="genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
<a href="py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="templateinheritance.html" title="Template Inheritance"
|
||||
<a href="blueprints.html" title="Modular Applications with Blueprints"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="viewdecorators.html" title="View Decorators"
|
||||
<a href="appcontext.html" title="The Application Context"
|
||||
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-1"><a href="index.html" accesskey="U">Patterns for Flask</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Form Validation with WTForms</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="">The Request Context</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section id="form-validation-with-wtforms">
|
||||
<h1>Form Validation with WTForms<a class="headerlink" href="#form-validation-with-wtforms" title="Link to this heading">¶</a></h1>
|
||||
<p>When you have to work with form data submitted by a browser view, code
|
||||
quickly becomes very hard to read. There are libraries out there designed
|
||||
to make this process easier to manage. One of them is <a class="reference external" href="https://wtforms.readthedocs.io/">WTForms</a> which we
|
||||
will handle here. If you find yourself in the situation of having many
|
||||
forms, you might want to give it a try.</p>
|
||||
<p>When you are working with WTForms you have to define your forms as classes
|
||||
first. I recommend breaking up the application into multiple modules
|
||||
(<a class="reference internal" href="packages.html"><span class="doc">Large Applications as Packages</span></a>) for that and adding a separate module for the
|
||||
forms.</p>
|
||||
<div class="admonition-getting-the-most-out-of-wtforms-with-an-extension admonition">
|
||||
<p class="admonition-title">Getting the most out of WTForms with an Extension</p>
|
||||
<p>The <a class="reference external" href="https://flask-wtf.readthedocs.io/">Flask-WTF</a> extension expands on this pattern and adds a
|
||||
few little helpers that make working with forms and Flask more
|
||||
fun. You can get it from <a class="reference external" href="https://pypi.org/project/Flask-WTF/">PyPI</a>.</p>
|
||||
</div>
|
||||
<section id="the-forms">
|
||||
<h2>The Forms<a class="headerlink" href="#the-forms" title="Link to this heading">¶</a></h2>
|
||||
<p>This is an example form for a typical registration page:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">wtforms</span><span class="w"> </span><span class="kn">import</span> <span class="n">Form</span><span class="p">,</span> <span class="n">BooleanField</span><span class="p">,</span> <span class="n">StringField</span><span class="p">,</span> <span class="n">PasswordField</span><span class="p">,</span> <span class="n">validators</span>
|
||||
|
||||
<span class="k">class</span><span class="w"> </span><span class="nc">RegistrationForm</span><span class="p">(</span><span class="n">Form</span><span class="p">):</span>
|
||||
<span class="n">username</span> <span class="o">=</span> <span class="n">StringField</span><span class="p">(</span><span class="s1">'Username'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Length</span><span class="p">(</span><span class="nb">min</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">25</span><span class="p">)])</span>
|
||||
<span class="n">email</span> <span class="o">=</span> <span class="n">StringField</span><span class="p">(</span><span class="s1">'Email Address'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Length</span><span class="p">(</span><span class="nb">min</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">35</span><span class="p">)])</span>
|
||||
<span class="n">password</span> <span class="o">=</span> <span class="n">PasswordField</span><span class="p">(</span><span class="s1">'New Password'</span><span class="p">,</span> <span class="p">[</span>
|
||||
<span class="n">validators</span><span class="o">.</span><span class="n">DataRequired</span><span class="p">(),</span>
|
||||
<span class="n">validators</span><span class="o">.</span><span class="n">EqualTo</span><span class="p">(</span><span class="s1">'confirm'</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s1">'Passwords must match'</span><span class="p">)</span>
|
||||
<span class="p">])</span>
|
||||
<span class="n">confirm</span> <span class="o">=</span> <span class="n">PasswordField</span><span class="p">(</span><span class="s1">'Repeat Password'</span><span class="p">)</span>
|
||||
<span class="n">accept_tos</span> <span class="o">=</span> <span class="n">BooleanField</span><span class="p">(</span><span class="s1">'I accept the TOS'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">DataRequired</span><span class="p">()])</span>
|
||||
<section id="the-request-context">
|
||||
<h1>The Request Context<a class="headerlink" href="#the-request-context" title="Link to this heading">¶</a></h1>
|
||||
<p>The request context keeps track of the request-level data during a
|
||||
request. Rather than passing the request object to each function that
|
||||
runs during a request, the <a class="reference internal" href="api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> and <a class="reference internal" href="api.html#flask.session" title="flask.session"><code class="xref py py-data docutils literal notranslate"><span class="pre">session</span></code></a> proxies
|
||||
are accessed instead.</p>
|
||||
<p>This is similar to <a class="reference internal" href="appcontext.html"><span class="doc">The Application Context</span></a>, which keeps track of the
|
||||
application-level data independent of a request. A corresponding
|
||||
application context is pushed when a request context is pushed.</p>
|
||||
<section id="purpose-of-the-context">
|
||||
<h2>Purpose of the Context<a class="headerlink" href="#purpose-of-the-context" title="Link to this heading">¶</a></h2>
|
||||
<p>When 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> application handles a request, it creates a
|
||||
<a class="reference internal" href="api.html#flask.Request" title="flask.Request"><code class="xref py py-class docutils literal notranslate"><span class="pre">Request</span></code></a> object based on the environment it received from the
|
||||
WSGI server. Because a <em>worker</em> (thread, process, or coroutine depending
|
||||
on the server) handles only one request at a time, the request data can
|
||||
be considered global to that worker during that request. Flask uses the
|
||||
term <em>context local</em> for this.</p>
|
||||
<p>Flask automatically <em>pushes</em> a request context when handling a request.
|
||||
View functions, error handlers, and other functions that run during a
|
||||
request will have access to the <a class="reference internal" href="api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> proxy, which points to
|
||||
the request object for the current request.</p>
|
||||
</section>
|
||||
<section id="lifetime-of-the-context">
|
||||
<h2>Lifetime of the Context<a class="headerlink" href="#lifetime-of-the-context" title="Link to this heading">¶</a></h2>
|
||||
<p>When a Flask application begins handling a request, it pushes a request
|
||||
context, which also pushes an <a class="reference internal" href="appcontext.html"><span class="doc">app context</span></a>. When the
|
||||
request ends it pops the request context then the application context.</p>
|
||||
<p>The context is unique to each thread (or other worker type).
|
||||
<a class="reference internal" href="api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a> cannot be passed to another thread, the other thread has
|
||||
a different context space and will not know about the request the parent
|
||||
thread was pointing to.</p>
|
||||
<p>Context locals are implemented using Python’s <a class="reference external" href="https://docs.python.org/3/library/contextvars.html#module-contextvars" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">contextvars</span></code></a> and
|
||||
Werkzeug’s <a class="reference external" href="https://werkzeug.palletsprojects.com/en/stable/local/#werkzeug.local.LocalProxy" title="(in Werkzeug v3.1.x)"><code class="xref py py-class docutils literal notranslate"><span class="pre">LocalProxy</span></code></a>. Python manages the
|
||||
lifetime of context vars automatically, and local proxy wraps that
|
||||
low-level interface to make the data easier to work with.</p>
|
||||
</section>
|
||||
<section id="manually-push-a-context">
|
||||
<h2>Manually Push a Context<a class="headerlink" href="#manually-push-a-context" title="Link to this heading">¶</a></h2>
|
||||
<p>If you try to access <a class="reference internal" href="api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a>, or anything that uses it, outside
|
||||
a request context, you’ll get this error message:</p>
|
||||
<div class="highlight-pytb notranslate"><div class="highlight"><pre><span></span><span class="x">RuntimeError: Working outside of request context.</span>
|
||||
|
||||
<span class="x">This typically means that you attempted to use functionality that</span>
|
||||
<span class="x">needed an active HTTP request. Consult the documentation on testing</span>
|
||||
<span class="x">for information about how to avoid this problem.</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This should typically only happen when testing code that expects an
|
||||
active request. One option is to use the
|
||||
<a class="reference internal" href="api.html#flask.Flask.test_client" title="flask.Flask.test_client"><code class="xref py py-meth docutils literal notranslate"><span class="pre">test</span> <span class="pre">client</span></code></a> to simulate a full request. Or
|
||||
you can use <a class="reference internal" href="api.html#flask.Flask.test_request_context" title="flask.Flask.test_request_context"><code class="xref py py-meth docutils literal notranslate"><span class="pre">test_request_context()</span></code></a> in a <code class="docutils literal notranslate"><span class="pre">with</span></code> block, and
|
||||
everything that runs in the block will have access to <a class="reference internal" href="api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a>,
|
||||
populated with your test data.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">generate_report</span><span class="p">(</span><span class="n">year</span><span class="p">):</span>
|
||||
<span class="nb">format</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"format"</span><span class="p">)</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">test_request_context</span><span class="p">(</span>
|
||||
<span class="s2">"/make_report/2017"</span><span class="p">,</span> <span class="n">query_string</span><span class="o">=</span><span class="p">{</span><span class="s2">"format"</span><span class="p">:</span> <span class="s2">"short"</span><span class="p">}</span>
|
||||
<span class="p">):</span>
|
||||
<span class="n">generate_report</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you see that error somewhere else in your code not related to
|
||||
testing, it most likely indicates that you should move that code into a
|
||||
view function.</p>
|
||||
<p>For information on how to use the request context from the interactive
|
||||
Python shell, see <a class="reference internal" href="shell.html"><span class="doc">Working with the Shell</span></a>.</p>
|
||||
</section>
|
||||
<section id="how-the-context-works">
|
||||
<h2>How the Context Works<a class="headerlink" href="#how-the-context-works" title="Link to this heading">¶</a></h2>
|
||||
<p>The <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">Flask.wsgi_app()</span></code></a> method is called to handle each request. It
|
||||
manages the contexts during the request. Internally, the request and
|
||||
application contexts work like stacks. When contexts are pushed, the
|
||||
proxies that depend on them are available and point at information from
|
||||
the top item.</p>
|
||||
<p>When the request starts, a <a class="reference internal" href="api.html#flask.ctx.RequestContext" title="flask.ctx.RequestContext"><code class="xref py py-class docutils literal notranslate"><span class="pre">RequestContext</span></code></a> is created and
|
||||
pushed, which creates and pushes an <a class="reference internal" href="api.html#flask.ctx.AppContext" title="flask.ctx.AppContext"><code class="xref py py-class docutils literal notranslate"><span class="pre">AppContext</span></code></a> first if
|
||||
a context for that application is not already the top context. While
|
||||
these contexts are pushed, the <a class="reference internal" href="api.html#flask.current_app" title="flask.current_app"><code class="xref py py-data docutils literal notranslate"><span class="pre">current_app</span></code></a>, <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>,
|
||||
<a class="reference internal" href="api.html#flask.request" title="flask.request"><code class="xref py py-data docutils literal notranslate"><span class="pre">request</span></code></a>, and <a class="reference internal" href="api.html#flask.session" title="flask.session"><code class="xref py py-data docutils literal notranslate"><span class="pre">session</span></code></a> proxies are available to the
|
||||
original thread handling the request.</p>
|
||||
<p>Other contexts may be pushed to change the proxies during a request.
|
||||
While this is not a common pattern, it can be used in advanced
|
||||
applications to, for example, do internal redirects or chain different
|
||||
applications together.</p>
|
||||
<p>After the request is dispatched and a response is generated and sent,
|
||||
the request context is popped, which then pops the application context.
|
||||
Immediately before they are popped, the <a class="reference internal" href="api.html#flask.Flask.teardown_request" title="flask.Flask.teardown_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">teardown_request()</span></code></a>
|
||||
and <a class="reference internal" href="api.html#flask.Flask.teardown_appcontext" title="flask.Flask.teardown_appcontext"><code class="xref py py-meth docutils literal notranslate"><span class="pre">teardown_appcontext()</span></code></a> functions are executed. These
|
||||
execute even if an unhandled exception occurred during dispatch.</p>
|
||||
</section>
|
||||
<section id="callbacks-and-errors">
|
||||
<span id="id1"></span><h2>Callbacks and Errors<a class="headerlink" href="#callbacks-and-errors" title="Link to this heading">¶</a></h2>
|
||||
<p>Flask dispatches a request in multiple stages which can affect the
|
||||
request, response, and how errors are handled. The contexts are active
|
||||
during all of these stages.</p>
|
||||
<p>A <a class="reference internal" href="api.html#flask.Blueprint" title="flask.Blueprint"><code class="xref py py-class docutils literal notranslate"><span class="pre">Blueprint</span></code></a> can add handlers for these events that are specific
|
||||
to the blueprint. The handlers for a blueprint will run if the blueprint
|
||||
owns the route that matches the request.</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>Before each request, <a class="reference internal" href="api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> functions are
|
||||
called. If one of these functions return a value, the other
|
||||
functions are skipped. The return value is treated as the response
|
||||
and the view function is not called.</p></li>
|
||||
<li><p>If the <a class="reference internal" href="api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> functions did not return a
|
||||
response, the view function for the matched route is called and
|
||||
returns a response.</p></li>
|
||||
<li><p>The return value of the view is converted into an actual response
|
||||
object and passed to the <a class="reference internal" href="api.html#flask.Flask.after_request" title="flask.Flask.after_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">after_request()</span></code></a>
|
||||
functions. Each function returns a modified or new response object.</p></li>
|
||||
<li><p>After the response is returned, the contexts are popped, which calls
|
||||
the <a class="reference internal" href="api.html#flask.Flask.teardown_request" title="flask.Flask.teardown_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">teardown_request()</span></code></a> and
|
||||
<a class="reference internal" href="api.html#flask.Flask.teardown_appcontext" title="flask.Flask.teardown_appcontext"><code class="xref py py-meth docutils literal notranslate"><span class="pre">teardown_appcontext()</span></code></a> functions. These functions are
|
||||
called even if an unhandled exception was raised at any point above.</p></li>
|
||||
</ol>
|
||||
<p>If an exception is raised before the teardown functions, Flask tries to
|
||||
match it with an <a class="reference internal" href="api.html#flask.Flask.errorhandler" title="flask.Flask.errorhandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">errorhandler()</span></code></a> function to handle the
|
||||
exception and return a response. If no error handler is found, or the
|
||||
handler itself raises an exception, Flask returns a generic
|
||||
<code class="docutils literal notranslate"><span class="pre">500</span> <span class="pre">Internal</span> <span class="pre">Server</span> <span class="pre">Error</span></code> response. The teardown functions are still
|
||||
called, and are passed the exception object.</p>
|
||||
<p>If debug mode is enabled, unhandled exceptions are not converted to a
|
||||
<code class="docutils literal notranslate"><span class="pre">500</span></code> response and instead are propagated to the WSGI server. This
|
||||
allows the development server to present the interactive debugger with
|
||||
the traceback.</p>
|
||||
<section id="teardown-callbacks">
|
||||
<h3>Teardown Callbacks<a class="headerlink" href="#teardown-callbacks" title="Link to this heading">¶</a></h3>
|
||||
<p>The teardown callbacks are independent of the request dispatch, and are
|
||||
instead called by the contexts when they are popped. The functions are
|
||||
called even if there is an unhandled exception during dispatch, and for
|
||||
manually pushed contexts. This means there is no guarantee that any
|
||||
other parts of the request dispatch have run first. Be sure to write
|
||||
these functions in a way that does not depend on other callbacks and
|
||||
will not fail.</p>
|
||||
<p>During testing, it can be useful to defer popping the contexts after the
|
||||
request ends, so that their data can be accessed in the test function.
|
||||
Use the <a class="reference internal" href="api.html#flask.Flask.test_client" title="flask.Flask.test_client"><code class="xref py py-meth docutils literal notranslate"><span class="pre">test_client()</span></code></a> as a <code class="docutils literal notranslate"><span class="pre">with</span></code> block to preserve the
|
||||
contexts until the <code class="docutils literal notranslate"><span class="pre">with</span></code> block exits.</p>
|
||||
<div class="highlight-python 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="p">,</span> <span class="n">request</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">hello</span><span class="p">():</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'during view'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="s1">'Hello, World!'</span>
|
||||
|
||||
<span class="nd">@app</span><span class="o">.</span><span class="n">teardown_request</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">show_teardown</span><span class="p">(</span><span class="n">exception</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'after with block'</span><span class="p">)</span>
|
||||
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">test_request_context</span><span class="p">():</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'during with block'</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># teardown functions are called after the context with block exits</span>
|
||||
|
||||
<span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">test_client</span><span class="p">()</span> <span class="k">as</span> <span class="n">client</span><span class="p">:</span>
|
||||
<span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
|
||||
<span class="c1"># the contexts are not popped even though the request ended</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">path</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># the contexts are popped and teardown functions are called after</span>
|
||||
<span class="c1"># the client with block exits</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="in-the-view">
|
||||
<h2>In the View<a class="headerlink" href="#in-the-view" title="Link to this heading">¶</a></h2>
|
||||
<p>In the view function, the usage of this form looks like this:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">'/register'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">,</span> <span class="s1">'POST'</span><span class="p">])</span>
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">register</span><span class="p">():</span>
|
||||
<span class="n">form</span> <span class="o">=</span> <span class="n">RegistrationForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span> <span class="ow">and</span> <span class="n">form</span><span class="o">.</span><span class="n">validate</span><span class="p">():</span>
|
||||
<span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="n">form</span><span class="o">.</span><span class="n">email</span><span class="o">.</span><span class="n">data</span><span class="p">,</span>
|
||||
<span class="n">form</span><span class="o">.</span><span class="n">password</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>
|
||||
<span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
|
||||
<span class="n">flash</span><span class="p">(</span><span class="s1">'Thanks for registering'</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s1">'login'</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">'register.html'</span><span class="p">,</span> <span class="n">form</span><span class="o">=</span><span class="n">form</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Notice we’re implying that the view is using SQLAlchemy here
|
||||
(<a class="reference internal" href="sqlalchemy.html"><span class="doc">SQLAlchemy in Flask</span></a>), but that’s not a requirement, of course. Adapt
|
||||
the code as necessary.</p>
|
||||
<p>Things to remember:</p>
|
||||
<section id="signals">
|
||||
<h3>Signals<a class="headerlink" href="#signals" title="Link to this heading">¶</a></h3>
|
||||
<p>The following signals are sent:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>create the form from the request <code class="xref py py-attr docutils literal notranslate"><span class="pre">form</span></code> value if
|
||||
the data is submitted via the HTTP <code class="docutils literal notranslate"><span class="pre">POST</span></code> method and
|
||||
<code class="xref py py-attr docutils literal notranslate"><span class="pre">args</span></code> if the data is submitted as <code class="docutils literal notranslate"><span class="pre">GET</span></code>.</p></li>
|
||||
<li><p>to validate the data, call the <code class="xref py py-func docutils literal notranslate"><span class="pre">validate()</span></code>
|
||||
method, which will return <code class="docutils literal notranslate"><span class="pre">True</span></code> if the data validates, <code class="docutils literal notranslate"><span class="pre">False</span></code>
|
||||
otherwise.</p></li>
|
||||
<li><p>to access individual values from the form, access <code class="code docutils literal notranslate"><span class="pre">form.<NAME>.data</span></code>.</p></li>
|
||||
<li><p><a class="reference internal" href="api.html#flask.request_started" title="flask.request_started"><code class="xref py py-data docutils literal notranslate"><span class="pre">request_started</span></code></a> is sent before the <a class="reference internal" href="api.html#flask.Flask.before_request" title="flask.Flask.before_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">before_request()</span></code></a> functions
|
||||
are called.</p></li>
|
||||
<li><p><a class="reference internal" href="api.html#flask.request_finished" title="flask.request_finished"><code class="xref py py-data docutils literal notranslate"><span class="pre">request_finished</span></code></a> is sent after the <a class="reference internal" href="api.html#flask.Flask.after_request" title="flask.Flask.after_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">after_request()</span></code></a> functions
|
||||
are called.</p></li>
|
||||
<li><p><a class="reference internal" href="api.html#flask.got_request_exception" title="flask.got_request_exception"><code class="xref py py-data docutils literal notranslate"><span class="pre">got_request_exception</span></code></a> is sent when an exception begins to be handled, but
|
||||
before an <a class="reference internal" href="api.html#flask.Flask.errorhandler" title="flask.Flask.errorhandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">errorhandler()</span></code></a> is looked up or called.</p></li>
|
||||
<li><p><a class="reference internal" href="api.html#flask.request_tearing_down" title="flask.request_tearing_down"><code class="xref py py-data docutils literal notranslate"><span class="pre">request_tearing_down</span></code></a> is sent after the <a class="reference internal" href="api.html#flask.Flask.teardown_request" title="flask.Flask.teardown_request"><code class="xref py py-meth docutils literal notranslate"><span class="pre">teardown_request()</span></code></a>
|
||||
functions are called.</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
<section id="forms-in-templates">
|
||||
<h2>Forms in Templates<a class="headerlink" href="#forms-in-templates" title="Link to this heading">¶</a></h2>
|
||||
<p>Now to the template side. When you pass the form to the templates, you can
|
||||
easily render them there. Look at the following example template to see
|
||||
how easy this is. WTForms does half the form generation for us already.
|
||||
To make it even nicer, we can write a macro that renders a field with
|
||||
label and a list of errors if there are any.</p>
|
||||
<p>Here’s an example <code class="file docutils literal notranslate"><span class="pre">_formhelpers.html</span></code> template with such a macro:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">macro</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">field</span><span class="o">)</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">dt</span><span class="p">></span><span class="cp">{{</span> <span class="nv">field.label</span> <span class="cp">}}</span>
|
||||
<span class="p"><</span><span class="nt">dd</span><span class="p">></span><span class="cp">{{</span> <span class="nv">field</span><span class="o">(**</span><span class="nv">kwargs</span><span class="o">)|</span><span class="nf">safe</span> <span class="cp">}}</span>
|
||||
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">field.errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">errors</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">error</span> <span class="k">in</span> <span class="nv">field.errors</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">li</span><span class="p">></span><span class="cp">{{</span> <span class="nv">error</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
|
||||
<span class="p"></</span><span class="nt">dd</span><span class="p">></span>
|
||||
<span class="cp">{%</span> <span class="k">endmacro</span> <span class="cp">%}</span>
|
||||
</section>
|
||||
<section id="notes-on-proxies">
|
||||
<span id="id2"></span><h2>Notes On Proxies<a class="headerlink" href="#notes-on-proxies" title="Link to this heading">¶</a></h2>
|
||||
<p>Some of the objects provided by Flask are proxies to other objects. The
|
||||
proxies are accessed in the same way for each worker thread, but
|
||||
point to the unique object bound to each worker behind the scenes as
|
||||
described on this page.</p>
|
||||
<p>Most of the time you don’t have to care about that, but there are some
|
||||
exceptions where it is good to know that this object is actually a proxy:</p>
|
||||
<ul class="simple">
|
||||
<li><p>The proxy objects cannot fake their type as the actual object types.
|
||||
If you want to perform instance checks, you have to do that on the
|
||||
object being proxied.</p></li>
|
||||
<li><p>The reference to the proxied object is needed in some situations,
|
||||
such as sending <a class="reference internal" href="signals.html"><span class="doc">Signals</span></a> or passing data to a background
|
||||
thread.</p></li>
|
||||
</ul>
|
||||
<p>If you need to access the underlying object that is proxied, use the
|
||||
<code class="xref py py-meth docutils literal notranslate"><span class="pre">_get_current_object()</span></code> method:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">app</span> <span class="o">=</span> <span class="n">current_app</span><span class="o">.</span><span class="n">_get_current_object</span><span class="p">()</span>
|
||||
<span class="n">my_signal</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This macro accepts a couple of keyword arguments that are forwarded to
|
||||
WTForm’s field function, which renders the field for us. The keyword
|
||||
arguments will be inserted as HTML attributes. So, for example, you can
|
||||
call <code class="docutils literal notranslate"><span class="pre">render_field(form.username,</span> <span class="pre">class='username')</span></code> to add a class to
|
||||
the input element. Note that WTForms returns standard Python strings,
|
||||
so we have to tell Jinja2 that this data is already HTML-escaped with
|
||||
the <code class="docutils literal notranslate"><span class="pre">|safe</span></code> filter.</p>
|
||||
<p>Here is the <code class="file docutils literal notranslate"><span class="pre">register.html</span></code> template for the function we used above, which
|
||||
takes advantage of the <code class="file docutils literal notranslate"><span class="pre">_formhelpers.html</span></code> template:</p>
|
||||
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">from</span> <span class="s2">"_formhelpers.html"</span> <span class="k">import</span> <span class="nv">render_field</span> <span class="cp">%}</span>
|
||||
<span class="p"><</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">post</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.username</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.email</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.password</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.confirm</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.accept_tos</span><span class="o">)</span> <span class="cp">}}</span>
|
||||
<span class="p"></</span><span class="nt">dl</span><span class="p">></span>
|
||||
<span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">submit</span> <span class="na">value</span><span class="o">=</span><span class="s">Register</span><span class="p">></span>
|
||||
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For more information about WTForms, head over to the <a class="reference external" href="https://wtforms.readthedocs.io/">WTForms
|
||||
website</a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -164,38 +258,42 @@ website</a>.</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"/>
|
||||
|
||||
|
||||
<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="#">Form Validation with WTForms</a><ul>
|
||||
<li><a class="reference internal" href="#the-forms">The Forms</a></li>
|
||||
<li><a class="reference internal" href="#in-the-view">In the View</a></li>
|
||||
<li><a class="reference internal" href="#forms-in-templates">Forms in Templates</a></li>
|
||||
<li><a class="reference internal" href="#">The Request Context</a><ul>
|
||||
<li><a class="reference internal" href="#purpose-of-the-context">Purpose of the Context</a></li>
|
||||
<li><a class="reference internal" href="#lifetime-of-the-context">Lifetime of the Context</a></li>
|
||||
<li><a class="reference internal" href="#manually-push-a-context">Manually Push a Context</a></li>
|
||||
<li><a class="reference internal" href="#how-the-context-works">How the Context Works</a></li>
|
||||
<li><a class="reference internal" href="#callbacks-and-errors">Callbacks and Errors</a><ul>
|
||||
<li><a class="reference internal" href="#teardown-callbacks">Teardown Callbacks</a></li>
|
||||
<li><a class="reference internal" href="#signals">Signals</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#notes-on-proxies">Notes On Proxies</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="../index.html">Overview</a>
|
||||
<li><a href="index.html">Overview</a>
|
||||
<ul>
|
||||
<li><a href="index.html">Patterns for Flask</a>
|
||||
<ul>
|
||||
<li>Previous: <a href="viewdecorators.html" title="previous chapter">View Decorators</a>
|
||||
<li>Next: <a href="templateinheritance.html" title="next chapter">Template Inheritance</a></ul>
|
||||
</li>
|
||||
<li>Previous: <a href="appcontext.html" title="previous chapter">The Application Context</a>
|
||||
<li>Next: <a href="blueprints.html" title="next chapter">Modular Applications with Blueprints</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">
|
||||
<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>
|
||||
|
|
@ -211,4 +309,4 @@ website</a>.</p>
|
|||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue