[pre-commit.ci lite] apply automatic fixes

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

View file

@ -5,7 +5,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Blog Blueprint &#8212; Flask Documentation (3.2.x)</title>
<title>Application Setup &#8212; Flask Documentation (3.2.x)</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=6625fa76" />
<link rel="stylesheet" type="text/css" href="../_static/flask.css?v=b87c8d14" />
<script src="../_static/documentation_options.js?v=56528222"></script>
@ -15,8 +15,8 @@
<link rel="icon" href="../_static/shortcut-icon.png"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Make the Project Installable" href="install.html" />
<link rel="prev" title="Static Files" href="static.html" />
<link rel="next" title="Define and Access the Database" href="database.html" />
<link rel="prev" title="Project Layout" href="layout.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
@ -28,337 +28,167 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="install.html" title="Make the Project Installable"
<a href="database.html" title="Define and Access the Database"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="static.html" title="Static Files"
<a href="layout.html" title="Project Layout"
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>
<li class="nav-item nav-item-this"><a href="">Application Setup</a></li>
</ul>
</div>
</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>
<section id="application-setup">
<h1>Application Setup<a class="headerlink" href="#application-setup" title="Link to this heading"></a></h1>
<p>A Flask application is an instance of the <a class="reference internal" href="../api.html#flask.Flask" title="flask.Flask"><code class="xref py py-class docutils literal notranslate"><span class="pre">Flask</span></code></a> class.
Everything about the application, such as configuration and URLs, will
be registered with this class.</p>
<p>The most straightforward way to create a Flask application is to create
a global <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> instance directly at the top of your code, like
how the “Hello, World!” example did on the previous page. While this is
simple and useful in some cases, it can cause some tricky issues as the
project grows.</p>
<p>Instead of creating a <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> instance globally, you will create
it inside a function. This function is known as the <em>application
factory</em>. Any configuration, registration, and other setup the
application needs will happen inside the function, then the application
will be returned.</p>
<section id="the-application-factory">
<h2>The Application Factory<a class="headerlink" href="#the-application-factory" title="Link to this heading"></a></h2>
<p>Its time to start coding! Create the <code class="docutils literal notranslate"><span class="pre">flaskr</span></code> directory and add the
<code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file. The <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> serves double duty: it will
contain the application factory, and it tells Python that the <code class="docutils literal notranslate"><span class="pre">flaskr</span></code>
directory should be treated as a package.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>$ mkdir flaskr
</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>
<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/__init__.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">import</span><span class="w"> </span><span class="nn">os</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="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="k">def</span><span class="w"> </span><span class="nf">create_app</span><span class="p">(</span><span class="n">test_config</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="c1"># create and configure the app</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">instance_relative_config</span><span class="o">=</span><span class="kc">True</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">SECRET_KEY</span><span class="o">=</span><span class="s1">&#39;dev&#39;</span><span class="p">,</span>
<span class="n">DATABASE</span><span class="o">=</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">instance_path</span><span class="p">,</span> <span class="s1">&#39;flaskr.sqlite&#39;</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">test_config</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># load the instance config, if it exists, when not testing</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="s1">&#39;config.py&#39;</span><span class="p">,</span> <span class="n">silent</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># load the test config if passed in</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">test_config</span><span class="p">)</span>
<span class="c1"># ensure the instance folder exists</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">instance_path</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="c1"># a simple page that says hello</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/hello&#39;</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="k">return</span> <span class="s1">&#39;Hello, World!&#39;</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>
<p><code class="docutils literal notranslate"><span class="pre">create_app</span></code> is the application factory function. Youll add to it
later in the tutorial, but it already does a lot.</p>
<ol class="arabic simple">
<li><p><code class="docutils literal notranslate"><span class="pre">app</span> <span class="pre">=</span> <span class="pre">Flask(__name__,</span> <span class="pre">instance_relative_config=True)</span></code> creates 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> instance.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">__name__</span></code> is the name of the current Python module. The app
needs to know where its located to set up some paths, and
<code class="docutils literal notranslate"><span class="pre">__name__</span></code> is a convenient way to tell it that.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">instance_relative_config=True</span></code> tells the app that
configuration files are relative to the
<a class="reference internal" href="../config.html#instance-folders"><span class="std std-ref">instance folder</span></a>. The instance folder
is located outside the <code class="docutils literal notranslate"><span class="pre">flaskr</span></code> package and can hold local
data that shouldnt be committed to version control, such as
configuration secrets and the database file.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="../api.html#flask.Config.from_mapping" title="flask.Config.from_mapping"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.config.from_mapping()</span></code></a> sets
some default configuration that the app will use:</p>
<ul class="simple">
<li><p><a class="reference internal" href="../config.html#SECRET_KEY" title="SECRET_KEY"><code class="xref py py-data docutils literal notranslate"><span class="pre">SECRET_KEY</span></code></a> is used by Flask and extensions to keep data
safe. Its set to <code class="docutils literal notranslate"><span class="pre">'dev'</span></code> to provide a convenient value
during development, but it should be overridden with a random
value when deploying.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">DATABASE</span></code> is the path where the SQLite database file will be
saved. Its under
<a class="reference internal" href="../api.html#flask.Flask.instance_path" title="flask.Flask.instance_path"><code class="xref py py-attr docutils literal notranslate"><span class="pre">app.instance_path</span></code></a>, which is the
path that Flask has chosen for the instance folder. Youll learn
more about the database in the next section.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="../api.html#flask.Config.from_pyfile" title="flask.Config.from_pyfile"><code class="xref py py-meth docutils literal notranslate"><span class="pre">app.config.from_pyfile()</span></code></a> overrides
the default configuration with values taken from the <code class="docutils literal notranslate"><span class="pre">config.py</span></code>
file in the instance folder if it exists. For example, when
deploying, this can be used to set a real <code class="docutils literal notranslate"><span class="pre">SECRET_KEY</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">test_config</span></code> can also be passed to the factory, and will be
used instead of the instance configuration. This is so the tests
youll write later in the tutorial can be configured
independently of any development values you have configured.</p></li>
</ul>
</li>
<li><p><a class="reference external" href="https://docs.python.org/3/library/os.html#os.makedirs" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">os.makedirs()</span></code></a> ensures that
<a class="reference internal" href="../api.html#flask.Flask.instance_path" title="flask.Flask.instance_path"><code class="xref py py-attr docutils literal notranslate"><span class="pre">app.instance_path</span></code></a> exists. Flask
doesnt create the instance folder automatically, but it needs to be
created because your project will create the SQLite database file
there.</p></li>
<li><p><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">&#64;app.route()</span></code></a> creates a simple route so you can
see the application working before getting into the rest of the
tutorial. It creates a connection between the URL <code class="docutils literal notranslate"><span class="pre">/hello</span></code> and a
function that returns a response, the string <code class="docutils literal notranslate"><span class="pre">'Hello,</span> <span class="pre">World!'</span></code> in
this case.</p></li>
</ol>
</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>
<section id="run-the-application">
<h2>Run The Application<a class="headerlink" href="#run-the-application" title="Link to this heading"></a></h2>
<p>Now you can run your application using the <code class="docutils literal notranslate"><span class="pre">flask</span></code> command. From the
terminal, tell Flask where to find your application, then run it in
debug mode. Remember, you should still be in the top-level
<code class="docutils literal notranslate"><span class="pre">flask-tutorial</span></code> directory, not the <code class="docutils literal notranslate"><span class="pre">flaskr</span></code> package.</p>
<p>Debug mode shows an interactive debugger whenever a page raises an
exception, and restarts the server whenever you make changes to the
code. You can leave it running and just reload the browser page as you
follow the tutorial.</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ flask --app flaskr run --debug
</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>
<p>Youll see output similar to this:</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>* Serving Flask app &quot;flaskr&quot;
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: nnn-nnn-nnn
</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>
<p>Visit <a class="reference external" href="http://127.0.0.1:5000/hello">http://127.0.0.1:5000/hello</a> in a browser and you should see the
“Hello, World!” message. Congratulations, youre now running your Flask
web application!</p>
<p>If another program is already using port 5000, youll see
<code class="docutils literal notranslate"><span class="pre">OSError:</span> <span class="pre">[Errno</span> <span class="pre">98]</span></code> or <code class="docutils literal notranslate"><span class="pre">OSError:</span> <span class="pre">[WinError</span> <span class="pre">10013]</span></code> when the
server tries to start. See <a class="reference internal" href="../server.html#address-already-in-use"><span class="std std-ref">Address already in use</span></a> for how to
handle that.</p>
<p>Continue to <a class="reference internal" href="database.html"><span class="doc">Define and Access the Database</span></a>.</p>
</section>
</section>
@ -370,21 +200,18 @@ to do before the project is complete.</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="#">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>
<li><a class="reference internal" href="#">Application Setup</a><ul>
<li><a class="reference internal" href="#the-application-factory">The Application Factory</a></li>
<li><a class="reference internal" href="#run-the-application">Run The Application</a></li>
</ul>
</li>
</ul>
@ -394,8 +221,8 @@ to do before the project is complete.</p>
<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>Previous: <a href="layout.html" title="previous chapter">Project Layout</a>
<li>Next: <a href="database.html" title="next chapter">Define and Access the Database</a></ul>
</li>
</ul>
</li>
@ -419,4 +246,4 @@ to do before the project is complete.</p>
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.1.3.
</div>
</body>
</html>
</html>