[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
|
|
@ -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