100 Days of Code - Day 2: Flask
Wednesday, January 2, 2019 @ 06:31:00 PM EST
Reading time ~5 minutes
I’m beginning a new project in my spare time for work. Many years ago the directive was handed down where our system operators could no longer have command line access to any of our systems. This did not bode well since the crucial component that needs constant monitoring is a Linux-based system with custom scripts designed to allow operators to do their jobs. At this time, another one of our engineers was able to piece together a “web app” that would allow the operators to perform these tasks through a web browser interface, without actually touching the command line itself. This satisfied the needs of the time.
Unfortunately, that engineer left the company shortly there after, and no one has maintained this application. I’ve taken a look into it and while I could add some functionality to it, it’s really an unwieldy mess to maintain. It’s a single file script containing everything it needs to run, laid out in, what I consider, a very unorganized mess that spits in the face of PEP 8 and 20. While I applaud the engineer for getting this working, I don’t think much thought was put into maintainability, which is something I try to consider when doing any kind of development.
So I’ve decided to reimplement this app in a modern Python Web Framework. I’ve used Bottle previously, which I enjoyed, but I thought I would give Flask a chance to see what it has to offer.
I’ll be working my way through two different Flask tutorials, the first is the official tutorial, which I’ve completed recently, and the other is the Flask Mega Tutorial by Miguel Grinberg. Both take slightly different approaches, so I’m trying to balance them as I work my way into Flask for my own project.
Like so many Python projects, I start by creating a virtual environment. I’m working in Windows 10 again, so I fire up a Powershell window, create a new folder for my project, and then create a venv
folder within that to house the virtual environment. I’ve never taken this approach before, and both tutorials do it. I’m not certain if this is a convention I just missed, but I like it and will be using it in the future. Typically I’ve been making the root folder the virtual environment folder, and then scaffolding from there, but that always seemed messy to me.
With the virtual environment setup, the first thing I do is update pip, because it’s always out of date. Then I install Flask.
python -m venv venv
.\venv\Scripts\activate
python -m pip install --upgrade pip
pip install flask
Next I create a folder which will hold the app
structure. Within this folder I create the “Application Factory”, which will spawn the Flask app and establish the app
folder as a Python package that can be loaded. To start I setup a very basic “Hello, World!” application in __init__.py
.
from flask import Flask
app = Flask(__name__)
Now I begin by figuring out my routes and templates. This is where the tutorials start do differ a bit. The official tutorial goes into database connections and blueprints. Both of which are great, but I don’t think will be needed for my project, at least not initially. So I follow Miguel’s tutorial and jump into creating routes.py
file in the app
folder. This will be used to define the routes that will be called by the users. For now, I’m just creating a basic route and template to get the structure started.
from flask import render_template
from app import app
@app.route('/')
@app.route('/index')
def index():
msg = {"text": "Hey, is this thing on?"}
return render_template('index.html', title="Test", msg=msg)
I need Flask’s render_template
function to return Jinja2 templates which can be leveraged to load data dynamically into the HTML code. Here we’ll simulate that by defining the msg
dictionary with the text
and data key value pair.
I want a place to store the templates, so I add a templates
folder under app
, and I create a very basic HTML/Jinja2 template, index.html
as specified in routes.py
.
<html>
<head>
{% if title %}
<title>{{ title }}</title>
{% else %}
<title>No Title Here</title>
{% endif %}
</head>
<body>
{% if msg %}
<h1>{{ msg.text }}</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
</body>
</html>
Jinja2 uses the {% ... %}
syntax for flow control and conditional statements, and the {{ }}
syntax to insert data into the HTML syntax. So if title
and msg
data is passed into the template, it will use it, but if it’s not it will use these default values. Here this isn’t very useful, but will help me later on.
There’s a few more steps before I can run the project. First, I need to add our routes
into the application factory, so I add a line into __init__.py
:
from flask import Flask
app = Flask(__name__)
from . import routes
Next I need to create two environment variables that will be used by the Flask framework. Again, this is where the two tutorials differ slightly. I opt to go with the “lazy loading” approach from the official tutorial opposed to Miguel’s suggestion of creating a one line Python file at the root of the project. I create the FLASK_APP
environment variable and set it’s value to app
, instead of the name of a Python script. Additionally, I setup the FLASK_ENV
variable and set it to development
, which starts Flask in debug mode.
$env:FLASK_APP = "app"
$env:FLASK_ENV = "development"
Now we’re ready to fire up the application by launching flask run
at the command line:
With the application running, I open a browser and I’m greeted with a lovely message:
That’s all I have for the day, a quick introduction to Flask that’s laying the ground work for future development. Tomorrow I hope to convert one of the routes from the old application to this Flask application.