Topic 9: Flask Applications
CITS3403 Agile Web Development
Adapted from the Flask Mega-Tutorial, by Miguel Grinberg: Semester 1, 2023
[Link]
Full Stack Development?
• Full stack development refers to developing all parts of a web
application: database, web server, application logic and front end.
• There are various “Full stacks” people use to develop:
– LAMP (Linux, Apache, MySQL and PHP)
– Ruby on Rails
– Django (Python)
• We’re going to use a number of tools in this unit:
– Flask: is a micro framework, that allows us to write our backend
in Python. It contains its own lightweight webserver for
development
– SQLite: is a lightweight database management system
– AJAX and JQuery: We have already seen these. We will use
these for making responsive web pages.
Full-stack development
• Fullstack development refers to developing every
part of the web application.
• It involves knowing all the technologies used from
mobile and front end, (HTML, CSS, javascript
frameworks) though to the backend logic, security
and database models used at the backend.
• Most developers are specialised in one part of the
stack.
Development environment
l A lot of web development is done from the command line,
since traditionally servers didn’t need a graphical front end.
l We can use Git to develop on laptops and push code to the
server, but we still rely heavily on command line tools.
l By now, every one should have a good text editor that does
syntax highlighting etc, some tool to allow them to compile
or run code with the command line, and a browser with
developer tools to view source, and debug javascript.
l You should also have a Git client to regularly commit your
code, and push to others.
Getting started with Flask
• Flask is a micro-framework to run on the
server, but it will run on any machine, and
has few dependencies.
• You will require python3 installed in your
operating environment, with pip.
• Use pip to install venv (virtual environment)
first and initialise the environment.
• Now install Flask. Any required modules will
be preserved by the virtual-environment.
• You can now run flask by typing flask run,
but the app doesn’t know what to run.
• Write the following into [Link], run the
program again.
• Use a browser to see your app in action!
([Link]
Application structure
• Our [Link] file doesn’t look like
much. It has a method to return ‘Hello
world!’ that is decorated with
@[Link](‘/’).
• app is an instance of the class
Flask. When it runs it listens for
requests, and if the route matches a
decorator, it executes the
corresponding function. A request
object is passed to the method.
• The return of the function becomes
the response.
• But this structure doesn’t scale well.
A better application structure
• A better structure is to create a package app
that will contain all the code we need for the
web app.
• It has an __init__.py file to create an
instance of the Flask class.
• We can create a file [Link], to contain
the request handlers.
• Finally, we need a file at the top level to
import the app. We set the system variable
FLASK_APP to the name of this file, so flask
knows what to run.
• Now the app package can contain files for
handling routes, modules, templates, tests
and anything else our application requires.
Server-side vs Client Side Rendering
• There are two approaches to serving
dynamic HTML:
• The server can build the HTML when it
receives the request and send to client.
• The server can send JS and an HTML
skeleton to the client, and the client can
then request JSON and build the HTML
using AJAX and JQuery.
• Server Side Rendering is the traditional
approach.
• Client Side Rendering is more flexible and
allows greater support for non-browser
devices.
• Flask supports both forms very well.
Client Side Rendering
• For client side rendering, the client first
needs to access a HTML template and
some JS.
• Flask projects have a static directory to
serve non-dynamic files, including HTML,
CSS, JS and images.
• We can then have flask redirect all
requests for a file to the static html we
want to serve.
• We now need HTML and JS for the client
HTML and JS for the Client
HTML and JS for the Client
And routes to service the AJAX request
[Link]
Server-side Rendering
• Server-side rendering listen for requests,
and uses python functions to build html
pages to return as a response.
• However, this mixes the logic and the
presentation.
• A typical pattern to use is to have a
template or views directory to have some
html that references objects and code, and a
rendering function that will take a template
and some data and builds the html
dynamically.
• Flask uses jinja for this task, but there are
many alternatives (pug, handlebars,
typescript)
Using Jinja
• We separate presentation and logic
by having a template directory to
contain annotated html, and specify a
rending function in the [Link] file
• When a request is received flask will
look for the matching template (in the
directory templates) and convert the
template to pure html using named
variables in the function.
• Two {{curly braces}} are used to
distinguish html from python
variables, and jinja does the
substitution
Jinja Loops and Conditionals
• Depending on the parameters
passed, we may want to display
the data differently.
• Jinja provides loops and
conditionals to allow the display
to adapt to data.
• For example, it is common to
pass in an array of objects, and
then present them in a table.
• Or we may want the display to
vary depending on who is
logged in.
Jinja Control Statements
• The syntax for control statements is to
use {% braces %}.
• Conditionals use if, else, elif, as
well as endif, since whitespace
scoping doesn’t work for html.
• We can also use for and while loops for
iterating through collections.
Jinja Inheritance
• Since we often want the titles, menus,
footers in an application to be the same,
we can have the templates inherit from
each other.
• The block xxxx is left unspecified for
other templates to fill in, and they can
extend the ase template by just
specifying how they would fill in xxxx
l This principle is
refered to as DRY:
dont repeat yourself
Forms
• To build PUT requests,
we typically use forms.
Flask uses the
WTForms module to Flask apps should have a secret key
validate Post Requests to protect against cross site request
forgery (CSRF). You can set in
• Install flask-wtf with [Link], but there are better ways.
pip and create a new
file in app, [Link]
• There are three parts to
the form: the form class,
the template containing
the form, and the route
for processing the form.
Rendering Forms
• Jinja works with flask-wtf to put
the appropriate input elements
in the page.
• The form.hidden_tag() is used
to protect against CSRF attacks
• The form elements are defined
by the [Link] class
• Attributes can be appended to
the elements in brackets.
• If a form doesn’t validate, the
errors are accessible in a list,
but are rendered server side.
Faster client side validation can
be applied using javascript.
• The url_for()maps back from the
function name to the route.
Processing Forms
• To process a form, we configure a
route for the POST method.
• We define an instance of the form
class, for both rendering and wrapping
posted data.
• A GET request won’t validate, so it will
jump to the last line, and render the
page.
• If a POST request validates, a flash
message is created, and the page is
redirected to the index.
• The flash messages are just a list that
can be accessed by other pages.
• To actually check a users passwords,
we need a database (next lecture).
App Configuration
• Storing the secret key in a source file isn’t
a good idea. Secret keys and user
credentials should always be manually
configured, and never part of the
repository. Setting them as system
variables is a good approach.
• Create a configuration file to store all
configuration variables. This can then be
loaded when the app runs.
• The environment variables can also store
database locations and credentials, and
keys for third party services
Debugging and the Flask Shell
• The Flask shell is a useful
way to test small functions
and their integration with
flask, without using a
browser.
• It loads the flask app, and all
the dependencies, but
doesn’t need the server
running. You can set the
shell context to have
variables predefined when
you start the shell.
• Debug mode is also very
useful. Set the system
variable FLASK_DEBUG=1
to get a trace of the errors
when the server crashes.
Suggested Reading
Read “What is Code” by Paul Ford:
[Link]