<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/blog.py</span></code></span><aclass="headerlink"href="#id1"title="Link to this code">¶</a></div>
<p>Import and register the blueprint from the factory using
<aclass="reference internal"href="../api.html#flask.Flask.register_blueprint"title="flask.Flask.register_blueprint"><codeclass="xref py py-meth docutils literal notranslate"><spanclass="pre">app.register_blueprint()</span></code></a>. Place the
new code at the end of the factory function before returning the app.</p>
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/__init__.py</span></code></span><aclass="headerlink"href="#id2"title="Link to this code">¶</a></div>
<p>Unlike the auth blueprint, the blog blueprint does not have a
<codeclass="docutils literal notranslate"><spanclass="pre">url_prefix</span></code>. So the <codeclass="docutils literal notranslate"><spanclass="pre">index</span></code> view will be at <codeclass="docutils literal notranslate"><spanclass="pre">/</span></code>, the <codeclass="docutils literal notranslate"><spanclass="pre">create</span></code>
view at <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">index</span></code> view defined below will be
<codeclass="docutils literal notranslate"><spanclass="pre">blog.index</span></code>. Some of the authentication views referred to a plain
associates the endpoint name <codeclass="docutils literal notranslate"><spanclass="pre">'index'</span></code> with the <codeclass="docutils literal notranslate"><spanclass="pre">/</span></code> url so that
<codeclass="docutils literal notranslate"><spanclass="pre">url_for('index')</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">url_for('blog.index')</span></code> will both work,
generating the same <codeclass="docutils literal notranslate"><spanclass="pre">/</span></code> URL either way.</p>
<p>In another application you might give the blog blueprint a
<codeclass="docutils literal notranslate"><spanclass="pre">url_prefix</span></code> and define a separate <codeclass="docutils literal notranslate"><spanclass="pre">index</span></code> view in the application
factory, similar to the <codeclass="docutils literal notranslate"><spanclass="pre">hello</span></code> view. Then the <codeclass="docutils literal notranslate"><spanclass="pre">index</span></code> and
<codeclass="docutils literal notranslate"><spanclass="pre">blog.index</span></code> endpoints and URLs would be different.</p>
</section>
<sectionid="index">
<h2>Index<aclass="headerlink"href="#index"title="Link to this heading">¶</a></h2>
<p>The index will show all of the posts, most recent first. A <codeclass="docutils literal notranslate"><spanclass="pre">JOIN</span></code> is
used so that the author information from the <codeclass="docutils literal notranslate"><spanclass="pre">user</span></code> table is
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/blog.py</span></code></span><aclass="headerlink"href="#id3"title="Link to this code">¶</a></div>
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/templates/blog/index.html</span></code></span><aclass="headerlink"href="#id4"title="Link to this code">¶</a></div>
<spanclass="p"><</span><spanclass="nt">div</span><spanclass="na">class</span><spanclass="o">=</span><spanclass="s">"about"</span><spanclass="p">></span>by <spanclass="cp">{{</span><spanclass="nv">post</span><spanclass="o">[</span><spanclass="s1">'username'</span><spanclass="o">]</span><spanclass="cp">}}</span> on <spanclass="cp">{{</span><spanclass="nv">post</span><spanclass="o">[</span><spanclass="s1">'created'</span><spanclass="o">]</span><spanclass="nv">.strftime</span><spanclass="o">(</span><spanclass="s1">'%Y-%m-%d'</span><spanclass="o">)</span><spanclass="cp">}}</span><spanclass="p"></</span><spanclass="nt">div</span><spanclass="p">></span>
<p>When a user is logged in, the <codeclass="docutils literal notranslate"><spanclass="pre">header</span></code> block adds a link to the
<codeclass="docutils literal notranslate"><spanclass="pre">create</span></code> view. When the user is the author of a post, they’ll see an
“Edit” link to the <codeclass="docutils literal notranslate"><spanclass="pre">update</span></code> view for that post. <codeclass="docutils literal notranslate"><spanclass="pre">loop.last</span></code> is a
special variable available inside <aclass="reference external"href="https://jinja.palletsprojects.com/templates/#for">Jinja for loops</a>. It’s used to
display a line after each post except the last one, to visually separate
them.</p>
</section>
<sectionid="create">
<h2>Create<aclass="headerlink"href="#create"title="Link to this heading">¶</a></h2>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">create</span></code> view works the same as the auth <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="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
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/blog.py</span></code></span><aclass="headerlink"href="#id5"title="Link to this code">¶</a></div>
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/templates/blog/create.html</span></code></span><aclass="headerlink"href="#id6"title="Link to this code">¶</a></div>
<h2>Update<aclass="headerlink"href="#update"title="Link to this heading">¶</a></h2>
<p>Both the <codeclass="docutils literal notranslate"><spanclass="pre">update</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">delete</span></code> views will need to fetch a <codeclass="docutils literal notranslate"><spanclass="pre">post</span></code>
by <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">post</span></code> and call
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/blog.py</span></code></span><aclass="headerlink"href="#id7"title="Link to this code">¶</a></div>
<spanclass="n">abort</span><spanclass="p">(</span><spanclass="mi">404</span><spanclass="p">,</span><spanclass="sa">f</span><spanclass="s2">"Post id </span><spanclass="si">{</span><spanclass="nb">id</span><spanclass="si">}</span><spanclass="s2"> doesn't exist."</span><spanclass="p">)</span>
<p><aclass="reference internal"href="../api.html#flask.abort"title="flask.abort"><codeclass="xref py py-func docutils literal notranslate"><spanclass="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. <codeclass="docutils literal notranslate"><spanclass="pre">404</span></code> means “Not Found”, and <codeclass="docutils literal notranslate"><spanclass="pre">403</span></code> means
“Forbidden”. (<codeclass="docutils literal notranslate"><spanclass="pre">401</span></code> means “Unauthorized”, but you redirect to the
login page instead of returning that status.)</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">check_author</span></code> argument is defined so that the function can be
used to get a <codeclass="docutils literal notranslate"><spanclass="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
doesn’t matter because they’re not modifying the post.</p>
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/blog.py</span></code></span><aclass="headerlink"href="#id8"title="Link to this code">¶</a></div>
<p>Unlike the views you’ve written so far, the <codeclass="docutils literal notranslate"><spanclass="pre">update</span></code> function takes
an argument, <codeclass="docutils literal notranslate"><spanclass="pre">id</span></code>. That corresponds to the <codeclass="docutils literal notranslate"><spanclass="pre"><int:id></span></code> in the route.
A real URL will look like <codeclass="docutils literal notranslate"><spanclass="pre">/1/update</span></code>. Flask will capture the <codeclass="docutils literal notranslate"><spanclass="pre">1</span></code>,
ensure it’s an <aclass="reference external"href="https://docs.python.org/3/library/functions.html#int"title="(in Python v3.13)"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">int</span></code></a>, and pass it as the <codeclass="docutils literal notranslate"><spanclass="pre">id</span></code> argument. If you
don’t specify <codeclass="docutils literal notranslate"><spanclass="pre">int:</span></code> and instead do <codeclass="docutils literal notranslate"><spanclass="pre"><id></span></code>, it will be a string.
To generate a URL to the update page, <aclass="reference internal"href="../api.html#flask.url_for"title="flask.url_for"><codeclass="xref py py-func docutils literal notranslate"><spanclass="pre">url_for()</span></code></a> needs to be passed
the <codeclass="docutils literal notranslate"><spanclass="pre">id</span></code> so it knows what to fill in:
<codeclass="docutils literal notranslate"><spanclass="pre">url_for('blog.update',</span><spanclass="pre">id=post['id'])</span></code>. This is also in the
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">create</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">update</span></code> views look very similar. The main
difference is that the <codeclass="docutils literal notranslate"><spanclass="pre">update</span></code> view uses a <codeclass="docutils literal notranslate"><spanclass="pre">post</span></code> object and an
<codeclass="docutils literal notranslate"><spanclass="pre">UPDATE</span></code> query instead of an <codeclass="docutils literal notranslate"><spanclass="pre">INSERT</span></code>. With some clever refactoring,
you could use one view and template for both actions, but for the
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/templates/blog/update.html</span></code></span><aclass="headerlink"href="#id9"title="Link to this code">¶</a></div>
<spanclass="p"><</span><spanclass="nt">input</span><spanclass="na">class</span><spanclass="o">=</span><spanclass="s">"danger"</span><spanclass="na">type</span><spanclass="o">=</span><spanclass="s">"submit"</span><spanclass="na">value</span><spanclass="o">=</span><spanclass="s">"Delete"</span><spanclass="na">onclick</span><spanclass="o">=</span><spanclass="s">"return confirm('Are you sure?');"</span><spanclass="p">></span>
<p>This template has two forms. The first posts the edited data to the
current page (<codeclass="docutils literal notranslate"><spanclass="pre">/<id>/update</span></code>). The other form contains only a button
and specifies an <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">{{</span><spanclass="pre">request.form['title']</span><spanclass="pre">or</span><spanclass="pre">post['title']</span><spanclass="pre">}}</span></code> is used to
choose what data appears in the form. When the form hasn’t been
submitted, the original <codeclass="docutils literal notranslate"><spanclass="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
<codeclass="docutils literal notranslate"><spanclass="pre">request.form</span></code> is used instead. <aclass="reference internal"href="../api.html#flask.request"title="flask.request"><codeclass="xref py py-data docutils literal notranslate"><spanclass="pre">request</span></code></a> is another variable
that’s automatically available in templates.</p>
</section>
<sectionid="delete">
<h2>Delete<aclass="headerlink"href="#delete"title="Link to this heading">¶</a></h2>
<p>The delete view doesn’t have its own template, the delete button is part
of <codeclass="docutils literal notranslate"><spanclass="pre">update.html</span></code> and posts to the <codeclass="docutils literal notranslate"><spanclass="pre">/<id>/delete</span></code> URL. Since there
is no template, it will only handle the <codeclass="docutils literal notranslate"><spanclass="pre">POST</span></code> method and then redirect
to the <codeclass="docutils literal notranslate"><spanclass="pre">index</span></code> view.</p>
<divclass="code-block-caption"><spanclass="caption-text"><codeclass="docutils literal notranslate"><spanclass="pre">flaskr/blog.py</span></code></span><aclass="headerlink"href="#id10"title="Link to this code">¶</a></div>
<spanclass="n">db</span><spanclass="o">.</span><spanclass="n">execute</span><spanclass="p">(</span><spanclass="s1">'DELETE FROM post WHERE id = ?'</span><spanclass="p">,</span><spanclass="p">(</span><spanclass="nb">id</span><spanclass="p">,))</span>