Building your first Web app with Flask

Building your first Web app with Flask

rendering templates, view functions, conditional statements, dictionaries...

ยท

11 min read

Good day ardent readers, it's been a while since my last blog and I'm sure y'all have been developing yourselves to become better and also learning new stuff

Well, I have been doing just that! Building on my Python programming background and experience with using Django, a powerful python framework for building and deploying web apps, I decided to learn Flask

Just want the code? - https://github.com/starlingvibes/flask-webapp

So what is Flask?

PngItem_1595948.png Flask is a python framework just like Django but it's stand-out feature is it's ability in letting the developers take the driver's seat and have full control of their applications.

Do you like relational databases? Or maybe you prefer a NoSQL database? Or probably your own homegrown database engine?

No problems, Flask allows you choose the components of your application, no questions asked!

Installing Flask

The most convenient way of installing Flask is via a virtual environment. A virtual environment is a copy of the Python interpreter into which you can install packages privately without affecting the global Python interpreter installed in your system To create a virtual environment, run: python3 -m venv *env-name* where env-name is the name of the virtual environment you'd like to create Make sure your current directory is set to that of your project, and then run this command: python3 -m venv venv After the command completes, voila! you will have a subdirectory with a brand-new virtual environment that contains a Python interpreter for exclusive use by this project

Activating the virtual environment

To activate the venv on a Linux or MacOs computer: source venv/bin/activate If you're on Windows: venv\Scripts\activate

NB: If you run into issues using the above command on Windows, escape the backslash like so: venv\\Scripts\\activate

Installing python packages with pip

Once you've activated the virtual environment, it's time to install Flask by running the following command python3 -m pip install flask On executing this command, pip will install Flask and all of its dependencies. You can list these dependencies by using the python3 -m pip freeze command

Flask application structure

Let's explore the different parts of a Flask application

Initialization

All Flask applications must create an application instance which is an object of the Flask class. This instance is usually created as follows:

from flask import Flask
app = Flask(__name__)

The name argument passed to the Flask class is used to determine the location of the application, which in turn allows it to locate other files that are part of the application, such as images and templates

Routes and View Functions

A route is an association between a URL and the function that handles it. This is important because Flask needs to know what code to run for each URL requested. The most convenient way to define a route is through the app.route decorator like so:

@app.route('/')
def index():
    return '<h1>Hello World!</h1>'

This registers the index() function as the handler for the application's root URL. These kinds of functions are called view functions. If the application is deployed on a server associated with www.example.com domain name, then navigating to http://www.example.com/ in your browser would trigger index() to run on the server

Since we'd be rendering some sort of user defined variable in the project as we'll see later, let's take a look at an example of a route that has a dynamic component

@app.route('/user/<name>')
def user(name):
    return '<h1>Hello, {}!</h1>'.format(name)

The portion of the route URL enclosed in angle brackets is the dynamic part and it's passed as an argument when the view function is invoked

Piecing it together

Having looked at the different parts of a Flask web application, let's piece it together

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>My first application!</h1>'

if __name__ == "__main__":
    app.run(debug=True)

The last two lines allow us run the application as a python script and setting the value of debug to True saves us the hassle of restarting our server whenever we make a change

Development web server

To start the application, make sure the virtual environment is activates and has Flask installed in it. Once that is satisfied, run the web server as follows: python3 *app-name*.py where app-name is the name of your Python file Once the server starts up, it goes into a loop that accepts requests and services them. This loop continues until you stop the application by pressing Ctrl+C. With the server running, open your web browser and type localhost:5000/ in the address bar

Basic Application Setup

You've done a good job setting up Flask and running your test application! Before we go further, let's take a minute to describe our application's functionality

  1. our application has access to the system's locale date/time (python's datetime module)
  2. our application displays a greeting based on the time of day (conditional statements)
  3. our application displays the day, date, month, year and time in a defined manner (dictionaries)
  4. our application is able to render user defined variables on /user/*var* (dynamic components)

The key to writing applications that are easy to maintain is to write clean and well-structured code. The obvious task is to generate a response to a request. This is enough for the simple requests but in many cases, a request also triggers a change in the state of the application and that's where moving the presentation logic into templates help improve the maintainability of the application.

A template is a file that contains the text of a response, with placeholder variables for the dynamic parts that will be known only in the context of a request. The process that replaces the variables with actual values and returns a final response string is called rendering. For the task of rendering templates, Flask uses a powerful template engine called Jinja2

Let's consider a template that implements the response returned by a user() view function that has a dynamic component, which is represented by a variable

<h1>Hello, {{ name }}!</h1>

Rendering templates

By default, Flask looks for templates in a templates subdirectory located inside the main applicaiton directory. Create a templates subdirectory and store the templates defined in the previous examples in it as index.html and user.html respectively The view functions in the application need to be modified to render these templates as such:

from flask import Flask, render_template
...
@app.route('/')
def index():
    return render_template('index.html')

@app.route('/user/<name>')
def user(name):
    return render_template('user.html', name=name)

The render_template() function provided by Flask integrates the Jinja2 template engine with the application. The function takes the filename of the application as its first argument, any additional arguments are key-value pairs that represent actual values for variables referenced in the template

Variables

The {{ name }} construct used in the template above references a variable, a special placeholder that tells the template engine that the value that goes in that place should be obtained from data provided at the time the template is rendered. Jinja2 recognizes variables of any type, even complex types such as lists, dictionaries, and objects The following are some more examples of variables used in templates:

<p>A value from a dictionary: {{ mydict['key'] }}.</p>
<p>A value from a list: {{ mylist[3] }}.</p>
<p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p>
<p>A value from an object's method: {{ myobj.somemethod() }}.</p>

Control Structures

Jinja2 offers several control structures that can be used to alter the flow of the template. The following example shows how conditional statements can be entered in a template:

{% if user %}
    Hello, {{ user }}!
{% else %}
    Hello, Stranger!
{% endif %}

Another common need in templates is to render a list of elements. Here's how this can be done using a for loop:

<ul>
    {% for comment in comments %}
        <li>{{ comment }}</li>
    {% endfor %}
</ul>

Jinja2 also supports macros and template inheritance, which are similar to functions and class inheritance in Python code respectively. We'd look at these in future blogs

GETTING OUR HANDS DIRTY

Before we get started building our webapp, let's take a moment to think about the functionality. We want to be able to be able to display Good *x*! where x could be morning, afternoon or evening depending on the time of day

Let's set up a skeleton for our app.py

from flask import Flask, render_template
import datetime

app = Flask(__name__)
@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)

And our templates/index.html like so:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Simple app</title>
</head>
<body>

</body>
</html>

If you're on VS Code, you can easily get a boilerplate by typing !. Thanks to Emmet. Running the web app would just display an empty page with a title of "Simple app"

To get our dynamic greeting functionality, we'd be employing the use of conditional statements. So let's grab the value of our hour variable from python's datetime module and get to work:

...
import datetime
app = Flask(__name__)
hour = datetime.datetime.now().hour

@app.route('/')
def index():
    return render_template('index.html', hour=hour)
...

What this is doing is fetch the current hour from Python's datetime module and then parse it to be rendered on the frontend. To get this displaying on our page:

...
<body>
    <p>{{ hour }}</p>
</body>
</html>

We don't just want to display the current hour on the screen though, we want to dynamically generate content based on it's value. To do that, let's throw in a bit of conditional statements in our HTML file

...
  <body>
    <h1>
      {% if (hour >= 0 and hour < 12) %} Good morning {{name|capitalize}}! {%
      elif (hour >= 12 and hour <= 17) %} Good afternoon {{name|capitalize}}! {%
      elif (hour > 17 and hour <= 23) %} Good evening {{name|capitalize}}! {%
      endif %}
    </h1>
</body>

What this does is check the value of the hour variable for different ranges and then display the appropriate message. Running our web app:

Screenshot_1.png

Congratulations on your first dynamic piece of code, now let's get to working on displaying the day, date, month, year and current time in a dynamic manner

Back to our app.py:

...
@app.route('/')
def index():
    hour = datetime.datetime.now().hour
    minute = datetime.datetime.now().minute
    second = datetime.datetime.now().second
    day = datetime.datetime.now().isoweekday()
    month = datetime.datetime.now().month
    date = datetime.datetime.now().day
    year = datetime.datetime.now().year
    current = datetime.datetime.now().year
    return render_template('index.html', hour=hour, current=current, day=day, date=date, month=month, 
    days=days, months=months, year=year, minute=minute, second=second)
...

What this does is get the various values we're interested in and then passing it to the frontend. The placeholder for these values in our index.html file would look like so:

...
  <body>
    <h1>
      {% if (hour >= 0 and hour < 12) %} Good morning {{name|capitalize}}! {%
      elif (hour >= 12 and hour <= 17) %} Good afternoon {{name|capitalize}}! {%
      elif (hour > 17 and hour <= 23) %} Good evening {{name|capitalize}}! {%
      endif %}
    </h1>
    <p>{{day}}, {{date}}th of {{month}} {{year}}</p>
    <p>{{hour}}:{{minute}}:{{second}}</p>
  </body>

Running the above code:

Screenshot_2.png

Awesome, our app is slowly taking form! But then, I'm sure you've noticed some issues, we're seeing 7 instead of Sunday and 4 instead of April. To fix this, we would be employing the use of dictionaries to map the numeric keys to their respective values. In our app.py, this would look like so:

days = {1:'Monday', 2: 'Tuesday', 3: 'Wednesday', 4: 'Thursday', 5: 'Friday', 6: 'Saturday', 7: 'Sunday'}
months = {
 1: 'January',
 2: 'February',
 3: 'March',
 4: 'April',
 5: 'May',
 6: 'June',
 7: 'July',
 8: 'August',
 9: 'September',
 10: 'October',
 11: 'November',
 12: 'December'
}

Nice, we've mapped the keys to their respective values. Now heading back to our index.html file, let's access the dictionaries' values using the key obtained from our module. This would work as follows:

...
    <p>{{days[day]}}, {{date}}th of {{months[month]}} {{year}}</p>
    <p>{{hour}}:{{minute}}:{{second}}</p>
...

Visualizing our new changes:

Screenshot_3.png

Perfect, you should be proud of yourself :-)! You must have noticed, we hardcoded the value for th in 24th. That's all good until the new month and our code reads - 1th of May ๐Ÿ˜‚ To fix that, we'd write a function that dynamically generates the suffix based on the current date. Our function would look like so:

def foo(date):
    date_suffix = ["th", "st", "nd", "rd"]

    if date % 10 in [1, 2, 3] and date not in [11, 12, 13]:
        return date_suffix[date % 10]
    else:
        return date_suffix[0]

suffix = foo(date)
...
return render_template('index.html', hour=hour, current=current, day=day, date=date, month=month, days=days, months=months, year=year, minute=minute, second=second, suffix=suffix)

We then invoke the function and set it to a variable suffix which is then passed to the frontend. Our new index.html should also reflect these changes:

...
<p>{{days[day]}}, {{date}}{{suffix}} of {{months[month]}} {{year}}</p>
    <p>{{hour}}:{{minute}}:{{second}}</p>
...

Phew ๐Ÿ˜ฐ, we're finally done. One more thing though, let's apply a bit of styling to make it look more interesting, or don't you think? ๐ŸŒš
To apply CSS files to our app, Flask looks in a special directory called static. So create this directory and add your CSS file in it, also the image for the project which can be accessed in this GitHub repository. To get Flask to access our files though, we need to import one more module from flask

from flask import Flask, render_template, url_for

Next, add the following code to the head of our index.html to link to the CSS.

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

Adding a bit of styling to your CSS file

body {
  height: 100%;
  background-color: rgb(86, 81, 81);
  background-image: url(./hero-bcg.jpeg);
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  position: relative;
}
h1 {
  text-align: center;
  font-size: 5rem;
  font-family: 'Times New Roman', Times, serif;
  color: rgb(255, 255, 255);
  padding: auto;
}
p {
  text-align: center;
  font-size: 1.2rem;
  color: rgb(229, 218, 218);
  font-weight: 400;
}

Save the app.py and navigate to your browser

Screenshot_4.png

I'm sure you agree that this looks so much better ๐Ÿ˜๐Ÿ˜๐Ÿ”ฅ. We'll look at setting up the dynamic component in the next blog, I believe this is enough for the day (take some time to digest them :-))

Additional resources

๐Ÿ”— Check out Flask's official documentation: https://flask.palletsprojects.com/en/2.1.x/

๐Ÿ”— Reading- Flask Web Development: Developing Web Applications with Python

๐Ÿ”— Video demo

Thank you for reading my post. If you are interested, here is a link to my other blog:
๐Ÿ•ธ How the web works

Lastly, I have summarized the code snippets we learned today in this GitHub repository.

Finally, the outro! It was a real long one to lay the foundations, thanks for stopping by to read and I hope you enjoyed reading just as much I enjoyed writing it. Unto the next one! ๐Ÿฅ‚

ย