Flask¶
In this reading, we will dig even deeper into Flask. We'll look at the
very import request
object redirects and flashing, which are very
cool. We'll also look at template inheritance in Jinja2.
Flask Tutorials¶
Please read the following. They are concise examples, but sometimes a little spartan, so I have additional notes below.
- HTTP methods. This refers to GET and POST, which can be confusing. The W3Schools has a good and concise summary of GET versus POST. That's a fairly short page; please read all of it.
- Flask - Sending Form Data to Template
- Flask - Redirect and Errors
- Flask - Message Flashing
The first reading on HTTP methods was assigned for the Flask 2 reading. We will talk about it in class, so please refresh your memory. The reading lists five HTTP methods. We'll talk about PUT and DELETE much later in the course (in the context of Ajax), and we'll never use HEAD, so you should focus on GET and POST.
Notes on HTTP Methods¶
- The different HTTP methods have to do with the format of how information is sent from the browser to the server and how the browser and server treat the data and the request.
- Clicking on a plain URL is always a GET request for that URL (endpoint), which is why GET is the most common method
- To use POST, you have to use a
FORM
with that method (or JavaScript, but we won't be doing that). - The Flask back-end routes can list the methods they support by using
the optional second argument to the
@app.route
decorator. - The data from the browser is in the
request
object (a "global" variable in Flask) - The method that was used is listed in the
request.method
- The data in a GET request is in
request.args
, which is a dictionary-like object. - The data in a POST request is in
request.form
, which is also a dictionary-like object.
Again, make sure you have read HTTP methods
Notes on Redirect¶
- The argument to a
redirect
is a URL, generated byurl_for()
- The response, including the URL, goes back to the browser,
- The browser then requests the specified URL
- That URL (presumably) creates the desired response.
So, the journey is like this:
- Browser requests a url, say
/foo
- Flask responds saying, "no, GET
/bar
instead" - Browser requests
/bar
- Flask responds to
/bar
- Browser displays that response
Here's a picture:
This whole sequence of round trips usually takes less than a second and the user doesn't even notice (though they may notice that the URL has changed.)
The purpose of a redirect is not for coding convenience but because
the second URL is the "right place to be". For example, a login route
(such as /login/
) might redirect to the user's "home" page, (such as
/user/fred
). That "right place" might be bookmarked, sent to
someone, etc.
Notes on Abort¶
The abort
function responds to the browser is one of a standard set
of errors, like 404 (not found) or 403 (forbidden). It works, but the
response is pretty minimal. It's often better to flash a nicer error
message and redirect them to a place where they can try again.
Notes on Flashing¶
Flashing is an incredible useful and convenient way to, basically, print messages to the user. Not long-term information, like the inventory of stuff in an e-commerce site, but info from a user-specific event or transaction, such as
- "added item to your cart"
- "invalid credit card number, please re-enter"
- "order submitted"
and so forth. You can see that these are one-off messages to the user. Users like getting confirmation that things worked, and information about why things didn't work. Flashing is perfect for that.
- The
flash()
function takes a message and squirrels it away where it can later be rendered onto the page. - The
get_flashed_messages()
function returns a list of message (strings) that can be rendered into a page using Jinja2. - If the page doesn't render the flashed messages, the user won't see them, so you must add that Jinja2 code to your HTML page(s)
- Often, we put the Jinja 2 code to show flashed messages in a base template page, from which other pages inherit (see below).
- The flashing mechanism can survive a redirect, which is a nice advantage over simpler systems.
- Flashing is based in part on sessions, which we'll talk more about later (though soon).
- To use sessions, you have to set
app.secret_key
. This is typically set to a random string. (They show this in the tutorial above, but they don't mention it.)
Here's a brief reminder about flashing is done. Imagine a "jar" of
messages (strings). Initially, the jar is empty. The flash(str)
function puts a string into the jar. The get_flashed_messages()
function takes all the strings out of the jar.
So, we put in our HTML template files some standard code that prints all the flashed messages, if any. Like this:
{% with messages = get_flashed_messages() %}
{% if messages %}
<div id="messages">
{% for msg in messages %}
<p>{{msg}}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
In our app.py
file, we can put calls to flash()
, like this:
@app.route('/bar/'):
def bar():
...
flash('added item to your cart')
...
return render_template('something.html')
Presumably, the something.html
file contains the HTML code above (or
a base template that it inherits from), and prints the
message(s). What is template inheritance? Let's talk about that
next. Inheritance means we can have a variety of templates, all of
which share certain common code like the flashing code.
Jinja2¶
Why use templating at all? Most websites have many pages, but with a common look and infrastructure (CSS files, JS files, etc). There's actually quite a lot of that boilerplate in this reading file (do a "view source" to see). I finally adopted a templating scheme for the CS 304 website, so if I decide to add or remove an infrastructure file, or to change some of the common markup, I don't have to update all umpteen pages of this site. It used to be a nightmare.
So, don't make my past mistake. If the common boilerplate is saved in a file, called a template, our web application (our Python code) can dynamically fill in the variable stuff (such as information pulled from the database). If we need to change the common stuff, it can easily be done by editing just one file.
Jinja2 Inheritance¶
Very often, the pages of a website have an overall theme, but with variations:
- All of the pages will have some standard infrastructure (CSS files, JavaScript files, links to external resources like Bootstrap or JQuery ...).
- All of the "top-level" pages will have the same nav bar, logo, and other kinds of content.
- Lower level pages will have variant nav bars, maybe smaller logos, links to top-level pages, etc.
- Every page will have its own title, header, etc.
How to balance all this? If we make a very fundamental change (maybe change our logo?) we might have to change all our templates. This is way better than having to update every page, but it still allows errors to creep in (you update some but not all of the templates).
A better, more sophisticated, approach is to use inheritance,
where a base template is very abstract, with chunks (blocks
)
that are filled in by the child templates. For example, the CS 304
site could have a base template that supplies the overall structure,
CSS, jQuery and JavaScript files. Then child templates could be used
for readings (like this file), lecture activities, assignments, and
other kinds of pages.
Jinja2 allows inheritance like this.
Primer on Jinja Templating. This does a nice job of describing inheritance
Inheritance¶
Suppose we have the following three templates:
The first is a general template for the whole site. Here's what it looks like:
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name=author content="Scott D. Anderson">
<title>{{title}}</title>
{% block headstuff %}{% endblock %}
</head>
<body>
{% block content %}
<h1>{{title}}</h1>
<article>Lorem ipsum ...</article>
{% endblock %}
<footer>
{% block footer %}
Default Copyright notices and stuff
{% endblock %}
</footer>
</body>
</html>
It can be rendered directly, but more importantly, the three named blocks can be overridden in the two child templates. The named blocks are
- headstuff, which is empty
- content, which is a generic page with just one placeholder: title
- footer, which has the copyright notice and such.
Here's the first child template, called reading.html
- It replaces all three named blocks.
- It replaces the headstuff block with something non-empty, thereby adding some CSS to the page
- It replaces the content with code that has three placeholders: title, classdate and article
- It replaces the footer with a specific copyright notice.
{% extends "base.html" %}
{# additional stuff for the head #}
{% block headstuff %}
<style> .optional { color: gray; }</style>
{% endblock %}
{# replaces default content block #}
{% block content %}
<h1>Reading on {{title}}</h1>
<p>Please read the following before class on {{ classdate }}
<article>{{ article }}</article>
{% endblock %}
{# replaces default footer #}
{% block footer %}
© 2019 Scott D. Anderson and the CS 304 staff
{% endblock %}
Now there are an additional tags (holes to fill), namely classdate
and article
Schematic¶
Here's an idea of the overall structure:
Note that everything in the child must be in a block. Anything else is ignored. The purpose of a child is to re-write one or more blocks. If you have no re-writes, the child is unnecessary.
Thus, children are very different from parents. I often see mistakes in student code where they copy/modify the base to be the child, but that's not right.
The parent has HTML with named blocks.
The children only has a specification of the parent, and replacements for the named blocks. The child doesn't have to replace all of the named blocks.