Web Development Using Flask - Part 3

in STEMGeeks4 months ago

Working With Forms and Sessions

We are back again for another article in introducing you to coding with Python, which has now taken us to web development and using Flask. This is the third article we have posted, where in the first two we introduced you to Flask with the basics and how to start using routes and templates to display your web pages.

If you need to catch up with our previous posts, head hear for our introduction, and here for part 2 of the series.

In this article we are going to introduce to you the next logical step(I think) in our web app by introducing Flask Forms. Forms allow the user to interact and add details to the web app. This could be in the form of contact details or login information. In our app, we are going to start with allowing a use to add details of when they went for a run.

We have learnt quite a bit already to make the introduction to Forms pretty simply, so it won't be too much more for you to learn to get them working on your app.

Forms Basics


If you haven't been following along with the previous articles, thats all good because we going to give you all the code to get things running from here. So open up your development system and we will get stated.

Start by creating a directory for our app to site in. We have been working with the app name of "flasking" so let's stick with this for now, and move into the directory:

mkdir flasking; cd flasking

Once you are in the new directory, create a virtual environment called venv and activate it:

python3 -m venv venv

source venv/bin/activate

Create a new requirements.txt file where we can add in all the required dependencies we need, including some others we may not get round to using just yet.

touch requirements.txt

Add in the following Modules to be installed as part of our virtual environment:

Click==7.0
Flask==1.1.1
itsdangerous==1.1.0
Jinja2==2.10.3
MarkupSafe==1.1.1
Werkzeug==0.16.0

Install all of the requirements we added to our file with the following command:

pip3 install -r requirements.txt

Great, now we can get started on our forms. Building on from what we learnt in our last article we will create the html template that will display the form. We then need to create a route and view function to then process the form.

If you did not read the previous article, we included a base.html template that we will use again today. If you already have the templates set up and installed, you are able to skip this step.

First make the templates directory and create a base.html file:

mkdir templates

touch templates/base.html

Open the base.html file with your text editor and add in our base template as we have below:

<!DOCTYPE html>
<html lang="en">
  <head>
    (html comment removed:  Required meta tags )
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Welcome To The Flasking App</title>
  </head>

  <body>
    <header>
      <h1>Flasking App</h1>
    </header>

    <main>
      (html comment removed:  child template )
      {% block content %}
      {% endblock %}
    </main>
  </body>
</html>

We can now add in the form which will allow users to add their run details in. Start by creating the file named add_run.html that will also sit in the templates directory:

touch templates/add_run.py

Now open the file with your text editor and add in the following template, that uses the base.html template we created earlier. As you can see, we are using the "form" element to define a form, which can contain any number of inputs that the user can provide. There are two key attributes often used with the "form" element, which are "text" to allow users to add details and "submit" to then allow the form to be submitted:

{% extends "base.html" %}

{% block content %}
<h1>Add a Run</h1>
<form method="post">
  <label for="typeOfRun">Type of Run(Easy|Long|Interval|Etc):</label>
  <input type="text" id="typeOfRun" name="type_of_run" />
  <br>
  <label for="numberOfKilometres">Number of Kilometres:</label>
  <input type="text" id="numberOfKilometres" name="number_of_kilometres" />
  <br>
  <label for="comments">Comments:</label>
  <input type="text" id="comments" name="comments" />
  <br>
  <input type="submit">
</form>
{% endblock %}

In HTML, the typical approach for defining an input is to create a "label" element to define a description of what to enter and then to have a separate "input" element for collecting the input:

  <label for="typeOfRun">Type of Run(Easy|Long|Interval|Etc):</label>
  <input type="text" id="typeOfRun" name="type_of_run" />

Different types of input elements can be used with different functionality including:

  • button
  • checkbox
  • date
  • email
  • file
  • number
  • password
  • radio
  • submit
  • text

We can now look at setting up our routes for the form. If you don't have the app.py script set up already, start by creating this file:

touch app.py

If you are working with the code we created in our previous article, all you will need to add is the route at the end of the file. Make sure you also add in the request module that is being imported at the start of the script:

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/add_run', methods=['GET', 'POST'])
def add_run():
    if request.method == 'POST':
        for key, value in request.form.items():
            print(f'{key}: {value}')
    return render_template('add_run.html')

We can now try this out by running the development environment

export FLASK_APP=app.py

flask run

If you add the development domain to your web browser, you should now be able to see the form we created:

http://localhost:5000/add_run

By filling out the form, you should then be able to see the details you added into the form is then posted to the logs on our development web server:

127.0.0.1 - - [04/Jun/2021 13:52:44] "GET /add_run HTTP/1.1" 200 -
type_of_run: Long
number_of_kilometres: 18
comments: This was tough
127.0.0.1 - - [04/Jun/2021 13:52:56] "POST /add_run HTTP/1.1" 200 -

This isn't really helpful as our form is not moving from the form we entered our details to. We also are not storing the data anywhere like in a database. This does show us the form is working properly, but now we will have a closer look at using sessions to store our data.

Introducing Sessions


Sessions allow you to store data in memory without needing to store the data in a database or text file. This is what we could use for a user that has not logged into our app, so we can store their history or what they are doing before they decide to commit to creating an account or something similar.

Session data in Flask is stored in a cryptographically signed cookie. We do this for security, and as we are only performing a test environment at the moment, we will do some less than secure processes to save time, but you should not have your cookie stored in plan text.

Before we get started with making changes to the app.py script, we need to get a secret token to allow our Flask app to store session data in the browser. We do this by using the Python interactive shell, by importing the secrets module and then printing out a 32 byte token.

Simply copy the commands below and you should get a similar output, which we will store in our app.py script:

python

Python 3.8.10 (tags/v3.8.10:3d8993a, May  3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import secrets
>>> print(secrets.token_bytes(32))
b'\x99\xad.\xec6\xa9\xfd\xd4p\xf7)\xde\x9e\xc5\xb7\x11\xde\x07`\xe2-\x83\xc4E\x8cw\xb5\xa2\xdbx\xde\xc3'

Now we have our token. We can make some changes to the app.py script. There is quite a few changes we have made, so we will list them all one by one:

  1. The import statement at the top of the script is adding in a few more modules. This includes the session module to allow us to record session data and redirect to allow the add_run page the then redirect to the runs page to then list all our runs.
  2. We have added in a app.secret_key variable. This is the secret we got in the previous step and we would not usually store a secret in plain text like this, but are only doing this to speed things up a little.
  3. The if statement in the add_run route now stores all our session data in variables, and then returns the list_runs route, that will of course, list our runs.
  4. Lastly, we then add in the list_runs route that we will create the template for shortly.
from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)

app.secret_key = '\x98)\x861hX[\xf1\xc5Z\[email protected]\xe7[K\xfe\xb5\xc7~\xb0\x99\x1e\x8f\xfem\xa6F\xc1&'

@app.route('/add_run', methods=['GET', 'POST'])
def add_run():
    if request.method == 'POST':
        for key, value in request.form.items():
            print(f'{key}: {value}')

        # Save the form data to the session object
        session['type_of_run'] = request.form['type_of_run']
        session['number_of_kilometres'] = request.form['number_of_kilometres']
        session['comments'] = request.form['comments']
        return redirect(url_for('list_runs'))

    return render_template('add_run.html')

@app.route('/runs/')
def list_runs():
    return render_template('runs.html')

Finally, we can now add in the runs.html template that will use the base template for our app. The template will use a table to display our data for us that is stored in sessions. Start by creating the file runs.html in the templates directory and then add in the following details:

{% extends "base.html" %}

{% block content %}
<div>
  <h1>List of Runs</h1>

  <table>
    (html comment removed:  Table Header Row )
    <thead>
      <tr>
        <th>Type Of Run</th>
        <th>Number of Kilometres</th>
        <th>Comments</th>
      </tr>
    </thead>

    (html comment removed:  Table Element (Row) )
    <tbody>
      <td>{{ session['type_of_run'] }}</td>
      <td>{{ session['number_of_kilometres'] }}</td>
      <td>${{ session['comments'] }}</td>
    </tbody>
  </table>
</div>
{% endblock %}

Save the file and we can now run our flask development web server. Browse to the http://localhost:5000/add_run url and add in some data and then click on submit. If all runs successfully, we should now be able to see the results in our runs.html page.

We have done a heap of work here and come a long way in our understanding of using Flask, include working with sessions, forms and extending our knowledge of templates. We are going to keep moving and implement testing as part of our next article so I hope you can join us next time.

Found this post useful? Kindly tap the up vote button below! :)

About The Author

I am a DevOps Engineer, Endurance Athlete and Author. As a DevOps Engineer I specialize in Linux and Open Source Applications. Particularly interested in Search Marketing and Analytic’s, and is currently developing my skills in devops, continuous integration, security, and development(Python).

Posted with STEMGeeks

Sort:  

Very useful. I've been curious about Flask for a while, but haven't check it out. I've built up the XHAUST site w/ Django -- it appears there are definitely some similarities between the two.

I think it is pretty similar to Django and a good place to start as it shows you th basics and let's you understand how things work. You then get a good appreciation of all the stuff that Django does for you.