flask/flask-docs/signals.html
2025-04-11 03:04:22 +00:00

422 lines
46 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Blog Blueprint &#8212; Flask Documentation (3.2.x)</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=6625fa76" />
<link rel="stylesheet" type="text/css" href="../_static/flask.css?v=b87c8d14" />
<script src="../_static/documentation_options.js?v=56528222"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<script data-project="flask" data-version="3.2.x" src="../_static/describe_version.js?v=fa7f30d0"></script>
<link rel="icon" href="../_static/shortcut-icon.png"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Make the Project Installable" href="install.html" />
<link rel="prev" title="Static Files" href="static.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="install.html" title="Make the Project Installable"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="static.html" title="Static Files"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Flask Documentation (3.2.x)</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Tutorial</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Blog Blueprint</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="blog-blueprint">
<h1>Blog Blueprint<a class="headerlink" href="#blog-blueprint" title="Link to this heading"></a></h1>
<p>Youll use the same techniques you learned about when writing the
authentication blueprint to write the blog blueprint. The blog should
list all posts, allow logged in users to create posts, and allow the
author of a post to edit or delete it.</p>
<p>As you implement each view, keep the development server running. As you
save your changes, try going to the URL in your browser and testing them
out.</p>
<section id="the-blueprint">
<h2>The Blueprint<a class="headerlink" href="#the-blueprint" title="Link to this heading"></a></h2>
<p>Define the blueprint and register it in the application factory.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/blog.py</span></code></span><a class="headerlink" href="#id1" title="Link to this code"></a></div>
<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="p">(</span>
<span class="n">Blueprint</span><span class="p">,</span> <span class="n">flash</span><span class="p">,</span> <span class="n">g</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="p">)</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">abort</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">flaskr.auth</span><span class="w"> </span><span class="kn">import</span> <span class="n">login_required</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">flaskr.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_db</span>
<span class="n">bp</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s1">&#39;blog&#39;</span><span class="p">,</span> <span class="vm">__name__</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>Import and register the blueprint from the factory using
<a class="reference internal" href="../api.html#flask.Flask.register_blueprint" title="flask.Flask.register_blueprint"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.register_blueprint()</span></code></a>. Place the
new code at the end of the factory function before returning the app.</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/__init__.py</span></code></span><a class="headerlink" href="#id2" title="Link to this code"></a></div>
<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="n">app</span> <span class="o">=</span> <span class="o">...</span>
<span class="c1"># existing code omitted</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.</span><span class="w"> </span><span class="kn">import</span> <span class="n">blog</span>
<span class="n">app</span><span class="o">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">blog</span><span class="o">.</span><span class="n">bp</span><span class="p">)</span>
<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="s1">&#39;index&#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">app</span>
</pre></div>
</div>
</div>
<p>Unlike the auth blueprint, the blog blueprint does not have a
<code class="docutils literal notranslate"><span class="pre">url_prefix</span></code>. So the <code class="docutils literal notranslate"><span class="pre">index</span></code> view will be at <code class="docutils literal notranslate"><span class="pre">/</span></code>, the <code class="docutils literal notranslate"><span class="pre">create</span></code>
view at <code class="docutils literal notranslate"><span class="pre">/create</span></code>, and so on. The blog is the main feature of Flaskr,
so it makes sense that the blog index will be the main index.</p>
<p>However, the endpoint for the <code class="docutils literal notranslate"><span class="pre">index</span></code> view defined below will be
<code class="docutils literal notranslate"><span class="pre">blog.index</span></code>. Some of the authentication views referred to a plain
<code class="docutils literal notranslate"><span class="pre">index</span></code> endpoint. <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">app.add_url_rule()</span></code></a>
associates the endpoint name <code class="docutils literal notranslate"><span class="pre">'index'</span></code> with the <code class="docutils literal notranslate"><span class="pre">/</span></code> url so that
<code class="docutils literal notranslate"><span class="pre">url_for('index')</span></code> or <code class="docutils literal notranslate"><span class="pre">url_for('blog.index')</span></code> will both work,
generating the same <code class="docutils literal notranslate"><span class="pre">/</span></code> URL either way.</p>
<p>In another application you might give the blog blueprint a
<code class="docutils literal notranslate"><span class="pre">url_prefix</span></code> and define a separate <code class="docutils literal notranslate"><span class="pre">index</span></code> view in the application
factory, similar to the <code class="docutils literal notranslate"><span class="pre">hello</span></code> view. Then the <code class="docutils literal notranslate"><span class="pre">index</span></code> and
<code class="docutils literal notranslate"><span class="pre">blog.index</span></code> endpoints and URLs would be different.</p>
</section>
<section id="index">
<h2>Index<a class="headerlink" href="#index" title="Link to this heading"></a></h2>
<p>The index will show all of the posts, most recent first. A <code class="docutils literal notranslate"><span class="pre">JOIN</span></code> is
used so that the author information from the <code class="docutils literal notranslate"><span class="pre">user</span></code> table is
available in the result.</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/blog.py</span></code></span><a class="headerlink" href="#id3" title="Link to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">index</span><span class="p">():</span>
<span class="n">db</span> <span class="o">=</span> <span class="n">get_db</span><span class="p">()</span>
<span class="n">posts</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="s1">&#39;SELECT p.id, title, body, created, author_id, username&#39;</span>
<span class="s1">&#39; FROM post p JOIN user u ON p.author_id = u.id&#39;</span>
<span class="s1">&#39; ORDER BY created DESC&#39;</span>
<span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">&#39;blog/index.html&#39;</span><span class="p">,</span> <span class="n">posts</span><span class="o">=</span><span class="n">posts</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/templates/blog/index.html</span></code></span><a class="headerlink" href="#id4" title="Link to this code"></a></div>
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s1">&#39;base.html&#39;</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">header</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>Posts<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">g.user</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;action&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">&#39;blog.create&#39;</span><span class="o">)</span> <span class="cp">}}</span><span class="s">&quot;</span><span class="p">&gt;</span>New<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</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="cp">{%</span> <span class="k">for</span> <span class="nv">post</span> <span class="k">in</span> <span class="nv">posts</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="cp">{{</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;title&#39;</span><span class="o">]</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;about&quot;</span><span class="p">&gt;</span>by <span class="cp">{{</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;username&#39;</span><span class="o">]</span> <span class="cp">}}</span> on <span class="cp">{{</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;created&#39;</span><span class="o">]</span><span class="nv">.strftime</span><span class="o">(</span><span class="s1">&#39;%Y-%m-%d&#39;</span><span class="o">)</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">g.user</span><span class="o">[</span><span class="s1">&#39;id&#39;</span><span class="o">]</span> <span class="o">==</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;author_id&#39;</span><span class="o">]</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;action&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">&#39;blog.update&#39;</span><span class="o">,</span> <span class="nv">id</span><span class="o">=</span><span class="nv">post</span><span class="o">[</span><span class="s1">&#39;id&#39;</span><span class="o">])</span> <span class="cp">}}</span><span class="s">&quot;</span><span class="p">&gt;</span>Edit<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;body&quot;</span><span class="p">&gt;</span><span class="cp">{{</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;body&#39;</span><span class="o">]</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">article</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nb">loop</span><span class="nv">.last</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">hr</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
<p>When a user is logged in, the <code class="docutils literal notranslate"><span class="pre">header</span></code> block adds a link to the
<code class="docutils literal notranslate"><span class="pre">create</span></code> view. When the user is the author of a post, theyll see an
“Edit” link to the <code class="docutils literal notranslate"><span class="pre">update</span></code> view for that post. <code class="docutils literal notranslate"><span class="pre">loop.last</span></code> is a
special variable available inside <a class="reference external" href="https://jinja.palletsprojects.com/templates/#for">Jinja for loops</a>. Its used to
display a line after each post except the last one, to visually separate
them.</p>
</section>
<section id="create">
<h2>Create<a class="headerlink" href="#create" title="Link to this heading"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">create</span></code> view works the same as the auth <code class="docutils literal notranslate"><span class="pre">register</span></code> view. Either
the form is displayed, or the posted data is validated and the post is
added to the database or an error is shown.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">login_required</span></code> decorator you wrote earlier is used on the blog
views. A user must be logged in to visit these views, otherwise they
will be redirected to the login page.</p>
<div class="literal-block-wrapper docutils container" id="id5">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/blog.py</span></code></span><a class="headerlink" href="#id5" title="Link to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/create&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">(</span><span class="s1">&#39;GET&#39;</span><span class="p">,</span> <span class="s1">&#39;POST&#39;</span><span class="p">))</span>
<span class="nd">@login_required</span>
<span class="k">def</span><span class="w"> </span><span class="nf">create</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">&#39;POST&#39;</span><span class="p">:</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span>
<span class="n">body</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;body&#39;</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="ow">not</span> <span class="n">title</span><span class="p">:</span>
<span class="n">error</span> <span class="o">=</span> <span class="s1">&#39;Title is required.&#39;</span>
<span class="k">if</span> <span class="n">error</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">flash</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="k">else</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="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="s1">&#39;INSERT INTO post (title, body, author_id)&#39;</span>
<span class="s1">&#39; VALUES (?, ?, ?)&#39;</span><span class="p">,</span>
<span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="n">g</span><span class="o">.</span><span class="n">user</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">])</span>
<span class="p">)</span>
<span class="n">db</span><span class="o">.</span><span class="n">commit</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">&#39;blog.index&#39;</span><span class="p">))</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">&#39;blog/create.html&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/templates/blog/create.html</span></code></span><a class="headerlink" href="#id6" title="Link to this code"></a></div>
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s1">&#39;base.html&#39;</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">header</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>New Post<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</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">&lt;</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;title&quot;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;title&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;title&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">request.form</span><span class="o">[</span><span class="s1">&#39;title&#39;</span><span class="o">]</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">required</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;body&quot;</span><span class="p">&gt;</span>Body<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;body&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;body&quot;</span><span class="p">&gt;</span><span class="cp">{{</span> <span class="nv">request.form</span><span class="o">[</span><span class="s1">&#39;body&#39;</span><span class="o">]</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;Save&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
</section>
<section id="update">
<h2>Update<a class="headerlink" href="#update" title="Link to this heading"></a></h2>
<p>Both the <code class="docutils literal notranslate"><span class="pre">update</span></code> and <code class="docutils literal notranslate"><span class="pre">delete</span></code> views will need to fetch a <code class="docutils literal notranslate"><span class="pre">post</span></code>
by <code class="docutils literal notranslate"><span class="pre">id</span></code> and check if the author matches the logged in user. To avoid
duplicating code, you can write a function to get the <code class="docutils literal notranslate"><span class="pre">post</span></code> and call
it from each view.</p>
<div class="literal-block-wrapper docutils container" id="id7">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/blog.py</span></code></span><a class="headerlink" href="#id7" title="Link to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">get_post</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">check_author</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="n">post</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="s1">&#39;SELECT p.id, title, body, created, author_id, username&#39;</span>
<span class="s1">&#39; FROM post p JOIN user u ON p.author_id = u.id&#39;</span>
<span class="s1">&#39; WHERE p.id = ?&#39;</span><span class="p">,</span>
<span class="p">(</span><span class="nb">id</span><span class="p">,)</span>
<span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
<span class="k">if</span> <span class="n">post</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">abort</span><span class="p">(</span><span class="mi">404</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;Post id </span><span class="si">{</span><span class="nb">id</span><span class="si">}</span><span class="s2"> doesn&#39;t exist.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">check_author</span> <span class="ow">and</span> <span class="n">post</span><span class="p">[</span><span class="s1">&#39;author_id&#39;</span><span class="p">]</span> <span class="o">!=</span> <span class="n">g</span><span class="o">.</span><span class="n">user</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">]:</span>
<span class="n">abort</span><span class="p">(</span><span class="mi">403</span><span class="p">)</span>
<span class="k">return</span> <span class="n">post</span>
</pre></div>
</div>
</div>
<p><a class="reference internal" href="../api.html#flask.abort" title="flask.abort"><code class="xref py py-func docutils literal notranslate"><span class="pre">abort()</span></code></a> will raise a special exception that returns an HTTP status
code. It takes an optional message to show with the error, otherwise a
default message is used. <code class="docutils literal notranslate"><span class="pre">404</span></code> means “Not Found”, and <code class="docutils literal notranslate"><span class="pre">403</span></code> means
“Forbidden”. (<code class="docutils literal notranslate"><span class="pre">401</span></code> means “Unauthorized”, but you redirect to the
login page instead of returning that status.)</p>
<p>The <code class="docutils literal notranslate"><span class="pre">check_author</span></code> argument is defined so that the function can be
used to get a <code class="docutils literal notranslate"><span class="pre">post</span></code> without checking the author. This would be useful
if you wrote a view to show an individual post on a page, where the user
doesnt matter because theyre not modifying the post.</p>
<div class="literal-block-wrapper docutils container" id="id8">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/blog.py</span></code></span><a class="headerlink" href="#id8" title="Link to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/&lt;int:id&gt;/update&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">(</span><span class="s1">&#39;GET&#39;</span><span class="p">,</span> <span class="s1">&#39;POST&#39;</span><span class="p">))</span>
<span class="nd">@login_required</span>
<span class="k">def</span><span class="w"> </span><span class="nf">update</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
<span class="n">post</span> <span class="o">=</span> <span class="n">get_post</span><span class="p">(</span><span class="nb">id</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">&#39;POST&#39;</span><span class="p">:</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span>
<span class="n">body</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;body&#39;</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="ow">not</span> <span class="n">title</span><span class="p">:</span>
<span class="n">error</span> <span class="o">=</span> <span class="s1">&#39;Title is required.&#39;</span>
<span class="k">if</span> <span class="n">error</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">flash</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="k">else</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="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="s1">&#39;UPDATE post SET title = ?, body = ?&#39;</span>
<span class="s1">&#39; WHERE id = ?&#39;</span><span class="p">,</span>
<span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">db</span><span class="o">.</span><span class="n">commit</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">&#39;blog.index&#39;</span><span class="p">))</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">&#39;blog/update.html&#39;</span><span class="p">,</span> <span class="n">post</span><span class="o">=</span><span class="n">post</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>Unlike the views youve written so far, the <code class="docutils literal notranslate"><span class="pre">update</span></code> function takes
an argument, <code class="docutils literal notranslate"><span class="pre">id</span></code>. That corresponds to the <code class="docutils literal notranslate"><span class="pre">&lt;int:id&gt;</span></code> in the route.
A real URL will look like <code class="docutils literal notranslate"><span class="pre">/1/update</span></code>. Flask will capture the <code class="docutils literal notranslate"><span class="pre">1</span></code>,
ensure its an <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>, and pass it as the <code class="docutils literal notranslate"><span class="pre">id</span></code> argument. If you
dont specify <code class="docutils literal notranslate"><span class="pre">int:</span></code> and instead do <code class="docutils literal notranslate"><span class="pre">&lt;id&gt;</span></code>, it will be a string.
To generate a URL to the update page, <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> needs to be passed
the <code class="docutils literal notranslate"><span class="pre">id</span></code> so it knows what to fill in:
<code class="docutils literal notranslate"><span class="pre">url_for('blog.update',</span> <span class="pre">id=post['id'])</span></code>. This is also in the
<code class="docutils literal notranslate"><span class="pre">index.html</span></code> file above.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">create</span></code> and <code class="docutils literal notranslate"><span class="pre">update</span></code> views look very similar. The main
difference is that the <code class="docutils literal notranslate"><span class="pre">update</span></code> view uses a <code class="docutils literal notranslate"><span class="pre">post</span></code> object and an
<code class="docutils literal notranslate"><span class="pre">UPDATE</span></code> query instead of an <code class="docutils literal notranslate"><span class="pre">INSERT</span></code>. With some clever refactoring,
you could use one view and template for both actions, but for the
tutorial its clearer to keep them separate.</p>
<div class="literal-block-wrapper docutils container" id="id9">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/templates/blog/update.html</span></code></span><a class="headerlink" href="#id9" title="Link to this code"></a></div>
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s1">&#39;base.html&#39;</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">header</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>Edit &quot;<span class="cp">{{</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;title&#39;</span><span class="o">]</span> <span class="cp">}}</span>&quot;<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</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">&lt;</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;title&quot;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;title&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;title&quot;</span>
<span class="na">value</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">request.form</span><span class="o">[</span><span class="s1">&#39;title&#39;</span><span class="o">]</span> <span class="k">or</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;title&#39;</span><span class="o">]</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">required</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&quot;body&quot;</span><span class="p">&gt;</span>Body<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;body&quot;</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;body&quot;</span><span class="p">&gt;</span><span class="cp">{{</span> <span class="nv">request.form</span><span class="o">[</span><span class="s1">&#39;body&#39;</span><span class="o">]</span> <span class="k">or</span> <span class="nv">post</span><span class="o">[</span><span class="s1">&#39;body&#39;</span><span class="o">]</span> <span class="cp">}}</span><span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;Save&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">hr</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">&#39;blog.delete&#39;</span><span class="o">,</span> <span class="nv">id</span><span class="o">=</span><span class="nv">post</span><span class="o">[</span><span class="s1">&#39;id&#39;</span><span class="o">])</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">input</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;danger&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;Delete&quot;</span> <span class="na">onclick</span><span class="o">=</span><span class="s">&quot;return confirm(&#39;Are you sure?&#39;);&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
<p>This template has two forms. The first posts the edited data to the
current page (<code class="docutils literal notranslate"><span class="pre">/&lt;id&gt;/update</span></code>). The other form contains only a button
and specifies an <code class="docutils literal notranslate"><span class="pre">action</span></code> attribute that posts to the delete view
instead. The button uses some JavaScript to show a confirmation dialog
before submitting.</p>
<p>The pattern <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">request.form['title']</span> <span class="pre">or</span> <span class="pre">post['title']</span> <span class="pre">}}</span></code> is used to
choose what data appears in the form. When the form hasnt been
submitted, the original <code class="docutils literal notranslate"><span class="pre">post</span></code> data appears, but if invalid form data
was posted you want to display that so the user can fix the error, so
<code class="docutils literal notranslate"><span class="pre">request.form</span></code> is used instead. <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> is another variable
thats automatically available in templates.</p>
</section>
<section id="delete">
<h2>Delete<a class="headerlink" href="#delete" title="Link to this heading"></a></h2>
<p>The delete view doesnt have its own template, the delete button is part
of <code class="docutils literal notranslate"><span class="pre">update.html</span></code> and posts to the <code class="docutils literal notranslate"><span class="pre">/&lt;id&gt;/delete</span></code> URL. Since there
is no template, it will only handle the <code class="docutils literal notranslate"><span class="pre">POST</span></code> method and then redirect
to the <code class="docutils literal notranslate"><span class="pre">index</span></code> view.</p>
<div class="literal-block-wrapper docutils container" id="id10">
<div class="code-block-caption"><span class="caption-text"><code class="docutils literal notranslate"><span class="pre">flaskr/blog.py</span></code></span><a class="headerlink" href="#id10" title="Link to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/&lt;int:id&gt;/delete&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">(</span><span class="s1">&#39;POST&#39;</span><span class="p">,))</span>
<span class="nd">@login_required</span>
<span class="k">def</span><span class="w"> </span><span class="nf">delete</span><span class="p">(</span><span class="nb">id</span><span class="p">):</span>
<span class="n">get_post</span><span class="p">(</span><span class="nb">id</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="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s1">&#39;DELETE FROM post WHERE id = ?&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nb">id</span><span class="p">,))</span>
<span class="n">db</span><span class="o">.</span><span class="n">commit</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">&#39;blog.index&#39;</span><span class="p">))</span>
</pre></div>
</div>
</div>
<p>Congratulations, youve now finished writing your application! Take some
time to try out everything in the browser. However, theres still more
to do before the project is complete.</p>
<p>Continue to <a class="reference internal" href="install.html"><span class="doc">Make the Project Installable</span></a>.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<span id="sidebar-top"></span>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/flask-vertical.png" alt="Logo of Flask"/>
</a></p>
<h3>Contents</h3>
<ul>
<li><a class="reference internal" href="#">Blog Blueprint</a><ul>
<li><a class="reference internal" href="#the-blueprint">The Blueprint</a></li>
<li><a class="reference internal" href="#index">Index</a></li>
<li><a class="reference internal" href="#create">Create</a></li>
<li><a class="reference internal" href="#update">Update</a></li>
<li><a class="reference internal" href="#delete">Delete</a></li>
</ul>
</li>
</ul>
<h3>Navigation</h3>
<ul>
<li><a href="../index.html">Overview</a>
<ul>
<li><a href="index.html">Tutorial</a>
<ul>
<li>Previous: <a href="static.html" title="previous chapter">Static Files</a>
<li>Next: <a href="install.html" title="next chapter">Make the Project Installable</a></ul>
</li>
</ul>
</li>
</ul>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script><div id="ethical-ad-placement"></div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2010 Pallets.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
</div>
</body>
</html>