Adding Static Files to Your Flask Project - Part 5

in STEMGeeks4 months ago (edited)

NOTE: Some of the HTML elements have not been formatted correctly in this post, so please review the code in GitHub as listed below if you are wanting the correct code for your project

If you've been working along with our project over the past few weeks, we have made some really cool progress with our Flask web application. Even though it is working pretty well, it doesn't really look that nice, so this article will do a little work on making our project look a little nicer. This is where we will introduce how static files are used by your Flask projects. As the name suggests, static files will remain the same and not change and can be used for things like images and style sheets and even HTML pages that are not changed like our templates are.

This article is number 17 in the series and if you would like to revert back to the previous articles, head over to our GitHub page where you will find all the code as well as links to all the other articles in the series:
https://github.com/vincesesto/python_study

If you've been following along so far with this project, you will not have to perform the following steps, but if you are new to the series, run the following set of commands in your working directory to get the "Flasking" web app up and running before we move further on with this project:

# Clone the repository:
git clone https://github.com/vincesesto/python_study.git

# Move into the root directory:
cd article_16/

# Create a virtual environment named venv
python3 -m venv venv

# Activate the virtual environment
source venv/bin/activate

# Install all of the requirements:
pip3 install -r requirements.txt

# Export where the app.py script is
export FLASK_APP = "app.py"

# Verify the flask web server runs without errors
flask run

# Open a web browser and enter the following URL to see the index page of the Flasking app
http://127.0.0.1:5000/

Everyone should now be on the same page and we can get started working with static files.

Start by moving into the root directory of the web application. Create a directory named static, and within that directory, create two further directories called css and img.

mkdir -p static/css static/img

If you guessed that CSS will be in the static/css directory and images will stay in the static/img directory, you guessed correctly. To allow the base template to use our static css files, we need to add the "class" attribute to the html elements, as you can see in the details we have below. You will need to open the templates/base.html file with your text editor and make the relevant changes to the body of the template. We have added the NEW comment in the lines that need to be changed:

<!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>Flasking App</title>

 
    <link rel="stylesheet" href="{{ url_for('static', filename='css/base_style.css') }}">

    {% block styling %}                                          
    {% endblock %}                                                 

  </head>

  <body>
    <header class="site-header">                 
      <nav class="nav">                                      
        <a class="nav-link logo">Flasking App</a>    
      </nav>                                                                 
    </header>

    <main class="content">
  
      {% block content %}
      {% endblock %}
    </main>
  </body>
</html>

We have a few changes that need to be made in here. Firstly in the head of the base template we have the following section which does two things. The first link we have set up points to our static css directory and the base_style.css file we will add shortly. The second line also allows each of the other templates the ability to use there own css files as well:

    <link rel="stylesheet" href="{{ url_for('static', filename='css/base_style.css') }}">

    {% block styling %}                                       
    {% endblock %}                                              

Further down in the body of the template, we then have the following section that includes the class="site-header" and allows each of the templates to then use the css specified in the head of the template:

    <header class="site-header">               
      <nav class="nav">                                   
        <a class="nav-link logo">Flasking App</a>   
      </nav>                                                              

Now you've added all the details to the base template, add in the css file we are going to use. Copy the file directly from our GitHub account to save some time, but you can also specify your own if you prefer:

wget https://raw.githubusercontent.com/vincesesto/python_study/main/article_17/static/css/base_style.css static/css/base_style.css

We can now make some changes to the index.html template. Open the template/index.html file with your text editor and make changes to have it look like the following. It is now set up to use

to separate the markup and use the css files we have added in the base template:

{% extends "base.html" %}

{% block content %}
<div class="container">
  <header class="content-text">
    <h1>Welcome to the <strong>Flasking App!</strong></h1>
    <p>Track your personal running and view historical charts.</p>
  </header>
</div>
{% endblock %}

We've made a few changes here, so save your work and run the test flask server with "flask run" and hopefully your index page should now look like the image in the following link:

https://github.com/vincesesto/python_study/blob/main/article_17/README.md

NOTE: We have been having issues loading images onto stem, so we are simply linking back to our GitHub account where we have added images for you to see what the page should not look like.

Adding Images, Navigation, Footers and More


Our app is starting to look a lot nicer and we can now start to work on some of the other pages to also improve how they look. As you might have suspected, we can store images as part of our static files which can then be referenced by our templates.

We will add an image to our index page, we created the img directory earlier, so we can now add an image into the directory that we will use by our index.html page. The following is what we have used as part of our app and is stored in our GitHub page, but feel free to use any image you like:

cp https://github.com/vincesesto/python_study/blob/main/article_17/static/img/ImageRunning.jpg
 css/img/ImageRunning.jpg

Now open the templates/index,html page with your text editor and make the following changes. As you can see after the header we have now added a new figure tag that now includes our img content and refers to our image we created above:

{% extends "base.html" %}

{% block content %}
<div class="container">
  <header class="content-text">
    <h1>Welcome to the <strong>Flasking App!</strong></h1>
    <p>Track your personal running and view historical charts.</p>
  </header>
  <figure class="content-image"> 
    <im g
      src="{{ url_for('static', filename='img/ImageRunning.jpg') }}"
      alt="Two guys running in the park">
  </figure>
</div>
{% endblock %}

Save the contents of the file, but before we test our changes we will also make some changes to the base.html file again to add in navigation and a footer for the page. We will also make some minor changes to the Add Runs and List Runs pages too.

Open the templates/base.html page and make the relevant changes to the header as we have below. Under the logo "Flasking App" details, there is now a nav list for the Home, Listing Runs and Adding in new runs:

    <header class="site-header">
      <nav class="nav">
        <a class="nav-link logo">Flasking App</a>
        <ul class="nav-list">
          <li class="nav-item"><a class="nav-link" href="{{ url_for('index') }}">Flasking Home</a></li>
          <li class="nav-item"><a class="nav-link" href="{{ url_for('list_runs') }}">List Runs</a></li>
          <li class="nav-item"><a class="nav-link" href="{{ url_for('add_run') }}">Add Runs</a></li>
        </ul>
      </nav>
    </header>

Move further down the page and add in the footer we have outlined below:

  <footer class="site-footer">
    <small>hive.blog 2021</small>
  </footer>

Save the changes to the base.html file and now open the templates/add_run.html page. Make the relevant changes below to allow the page to align in a table as well as using the new CSS we have added:

{% extends "base.html" %}

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

{% endblock %}

Lastly, open the templates/runs.html file and this will also use the CSS we have added as part of our changed in this article.

{% extends "base.html" %}

{% block content %}
<div class="stocks-container">
  <div class="stocks-list">
    <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 fire up the flask dev web server with "flask run".

View all the changes as they should look at the following link:
https://github.com/vincesesto/python_study/blob/main/article_17/README.md

Testing Our Changes


In our last article we set up some automatic tests that we could run after changes are implemented to make sure everything is working correctly. We have tested everything works fine but if we ran "pytest" from the root app directory, it would fail because we have made changes to the index.html file that now differs to what the tests are expecting.

If we had implemented test driven development as part of our app, we would change the tests first, make sure they fail and then change the code to match the tests.

Either way, the tests will not take long to correct. Open the tests/unit/test_app.py file and update the test_index_page() function too look like the one below:

def test_index_page():
    """
    GIVEN a Flask application
    WHEN the '/' page is requested (GET)
    THEN check the response is valid
    """
    with app.test_client() as client:
        response = client.get('/')
        assert response.status_code == 200
        assert b'Flasking App' in response.data
        assert b'Welcome to the <strong>Flasking App!</strong>' in response.data

This has been another big article with a lot of work done to help improve the way our app now looks.

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