Let's build a super cool Flask web app

Let's build a super cool Flask web app

Today, we will be harnessing the power of Python, Flask and APIs to build a super awesome website. We shall also learn a little bit about how Flask works, and how we can write Pythonic code inside HTML with the help of Jinja templates. So lets get started.

Flask

What is Flask

Flask is a super simple, lightweight web framework (source code) that allows us to build web applications with Python. It is super quick to get up and running with.

Flask maps routes on the website to individual Python functions. A route refers to any page on the website, and the function mapped to it defines how the page behaves. We can also render HTML pages from these functions, and even pass parameters to these pages. We will see this in action soon.

What is Jinja

Jinja is a template engine for python. We can write Pythonic code inside HTML, and Jinja will resolve that to generate pure HTML.

So what are we building

Today, we'll build a cool web app which shows the user a random cocktail, along with its ingredients and instructions on how to make it. We'll be using TheCocktailDB as our data source.

Create the directory structure

This is a very important step. In the root of the project (I'm assuming you are inside a folder dedicated to this project, do not name it flask), create a directory called website and a file main.py.

Inside the website directory, create 2 files __init__.py (init surrounded by double underscores) and views.py. Also create a directory called templates

Finally inside the templates directory, create base.html and home.html

Your file structure should look something like this

├── main.py
└── website
    ├── templates
    │   ├── base.html
    │   └── home.html
    ├── __init__.py
    └── views.py

Install dependencies

pip install Flask requests

Start writing code

Start with the HTML files. Go here and copy the contents of the file. Paste it in your base.html file. Most of this file is boilerplate HTML and some external CSS and JavaScript to make the site look better which we don't need to worry about. Look closely at 2 lines in particular.

<title>{% block title %}Home{% endblock %}</title>

This denotes the title of our webpage, and you can see Jinja templates in action. The block can be replaced if we want to show different content for different pages. In this case, we have only one page, called 'Home', so we shall not be changing this block.

<div class="container">
    {% block content %}{% endblock %}
</div>

We shall replace this block with some content later.

Now, go here and copy the code into your home.html file.

The first 2 lines tell us that this page extends base.html. We keep the title as "Home".

Then we start defining the content block. We have some basic HTML. But we also have some weird double curly brace syntax. This is also Jinja. For example,

<h1 align="center">{{ name }}</h1>

and

<img src="{{ image }}">

tells the Jinja engine to replace name and image later with the values of the variables name and image which we will pass in through the routes in Flask.

Next you can see that we can write for loops and if statements in our HTML code. This is mind-blowing. It is important to note that the variables ingredients, measures and instructions will be passed in from Flask. We have some basic logic to filter out empty ingredients and measures.

So we are done with the HTML structure.

Dive into Flask

In the __init__.py, we add some Flask starter code. Since this file is inside the website folder, it makes website a module which we can import from outside.

from flask import Flask

def create_app():
    app = Flask(__name__)

    from .views import views

    app.register_blueprint(views, url_prefix = '/')

    return app

Here, views refers to the views.py file, where we will add the logic of querying the API and getting all our required data from it.

Let's start implementing that now

from flask import Blueprint, render_template
import requests

First, we import dependencies

views = Blueprint('views', __name__)

This is the views which we import into __init__.py

@views.route('/')
def home():
    data = requests.get('https://www.thecocktaildb.com/api/json/v1/1/random.php').json()
    name = data['drinks'][0]['strDrink']
    image = data['drinks'][0]['strDrinkThumb']
    ingredients = []
    measures = []
    instructions = data['drinks'][0]['strInstructions']
    for i in range(1, 16):
        ingredients.append(data['drinks'][0][f'strIngredient{i}'])
        measures.append(data['drinks'][0][f'strMeasure{i}'])
    return render_template("home.html", name=name, image=image, ingredients=ingredients, measures=measures, instructions=instructions)

This is our home route. As we learnt, this route is mapped to a function called home() and this mapping is done by calling the decorator views.route('/') The / route is the default homepage of the website.

Now inside the function, we do some basic data extraction. If you look at the data object, it looks something like

{
  "drinks": [
    {
      "idDrink": "11242",
      "strDrink": "Chicago Fizz",
      "strDrinkAlternate": null,
      "strTags": null,
      "strVideo": null,
      "strCategory": "Ordinary Drink",
      "strIBA": null,
      "strAlcoholic": "Alcoholic",
      "strGlass": "Highball glass",
      "strInstructions": "Shake all ingredients (except carbonated water) with ice and strain into a highball glass over two ice cubes. Fill with carbonated water, stir, and serve.",
      ...
    }
  ]
}

We can very easily pull out the name, image, and instructions to prepare the drink.

name = data['drinks'][0]['strDrink']
image = data['drinks'][0]['strDrinkThumb']
instructions = data['drinks'][0]['strInstructions']

Also using a for loop, we can collects the ingredients and respective measures in two lists

for i in range(1, 16):
    ingredients.append(data['drinks'][0][f'strIngredient{i}'])
    measures.append(data['drinks'][0][f'strMeasure{i}'])

Some of these will be null but we handle that in the HTML Jinja templates.

Finally the last line passes in those variables to the render_template function. The values of these variables can then be used inside the home.html file. Note that in name=name, the first name refers to the one in the Jinja template, while the second name refers to the one defined in this function.

Finally in the main.py file add the following code

from website import create_app

app = create_app()

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

We import website as a module and create a Flask app. Then we run it with debug mode on. This helps us as a developer to see errors easily in our console.

Final steps

We can run our web app by running the following from our terminal

python main.py

We can access the app at localhost:5000

Conclusion

If you want to learn more about Flask, you can look here. It is really an awesome framework which can open up a lot of possibilities for Python developers.

You can, of course, look at the code for this project on GitHub. There is a hosted version at https://the-cocktail-app.onrender.com.

As always, keep building, keep learning and all the best.