Flask for Data Scientists (and other non web-devs).

Umar Khan
9 min readApr 7, 2021

I had been wanting to learn Flask for a while now, since I built my Dash based Crude Oil dashboard. While Dash was a nice and easy way to spin up interactive data visualization apps, I ran into its limitations fairly quickly. Flask is much more flexible and extensive and useful in a variety of use cases. It just made sense to have a web app development framework in one’s toolkit, as a general purpose utility with a variety of potential use cases.

Over the weekend, burned out from intense job searching, networking and take home assessments, I decided to take a break and do something fun. I had a couple of ideas for apps I had wanted to make for a while, so I decided it was a good time to take a nice detour into Flask. I’m glad I did it was alot of fun!

In this post, I hope to walk you through setting up a barebones Flask app. I have been following the Miguel Grinberg mega tutorial, which is one of the best written tutorials I have ever come across. I highly recommend refering to it to get more in depth or to cover advanced topics. My goal here is to distill his process and clarify it in places to get you up and running quick! To do so, I will build a simple to-do list app where I can enter tasks into a form and see the entries displayed on the page.

So what is a Flask app? A Flask app is an app written using the Python Flask framework, along with HTML and CSS to develop interactive browser based applications. When we run our Flask app, which is really just a Python script that can be run from the command line, it starts up a server that begins to listen to requests made to a given IP address (or we can run it through a dedicated server framework like nginx which is what is usually done in actual apps that are put into production). Flask apps then take requests from users’ browsers sent to the IP address, relay them to the server where they are processed, and send back the generated output to the user’s browser. This output can be text, images, HTML pages, anything really. The website Pintrest is the biggest example of a Flask app.

A good practice when making web apps is to divide your app into components. A standard pattern applied to web apps is the MVC pattern ( View, Container). Under this paradigm, a web app consists of three primary interrelated components.

  1. Model:

The way that our applications data is stored, structured and accessed.

2. View

The way in which it is presented to the user

3. Controller

The way in which the user can interact with our model, change what they are viewing and be presented with different types of data based on what they want.

While Flask does not force you to build according to this paradigm ( “Flask won’t make many decisions for you”, as the documentation says), following this pattern is generally a good idea. You want to split your app up into these three areas. So if you were to make lets say an app like Pintrest, you want to build a model for your data such as users, profiles, posts, clubs etc and think about what kinds of tables, attributes and relationships you want to build for this type of interdependant data. You want to then think about the appearance of your app and how the user can view this data. You also want to develop functionality allowing the user to interact with the app to control the appearance or the data presented.

Enough talk. Lets code.

Start a fresh repository. Create a virtual environment. Pip install ‘flask’. Next, make a folder called “app”, and inside that folder make a file “__init__.py”. We are building this app as a package; in python any folder that has a __init__.py file in it is treated as a package from which we can import things. We will later import the app from this package in our main execution module.

This is what the __init__.py file (and your repo so far) will look like:

Flask apps are instances of the Flask class imported from the flask library. We instantiate this class as “app” and pass into it __name__, which gives Flask the name and location of the current file which is where Flask will start when we run the app. The last line is needed to avoid circular imports, especially later when we import the app variable in the routes.py module(read more).

The routes.py module is the next file we make in the app directory. Routes is where we will essentially put together our view creation functionality. We define URLs that our server can respond to and how to respond to them inside view functions. Take a look:

Notice the ine @app.route(‘/’). In Flask we use decorators (that @ thing) to extend the “route” method of the flask app to define new endpoints and how to deal with them. We passed in ‘/’ to let Flask know that the function below will return the page we want to display on the root URL. If we want add additional pages, we simply make a new route using the decorator syntax and add the path to that page.

After the decorator, we define the function that will be run when the user goes to the end point, and whose return results will be sent to the User’s browser. These are called “view functions” since they return the content that the user will view. In our example, it only returns the string “Hello World”. Typically, view functions return HTML content; we will get to that in a minute. I just wanted to demonstrate the flow of your app’s functionality. One thing to note here is that each view function must have a unique name, and one app cannot have more than one view function with the same name added to it using the decorator method.

I bet you cant wait to try this app out! But before we can start up our app, we need to do two things:

  1. We need to set up the execution module I mentioned before. Make a new python file in the root folder of our repository, lets call it “project.py”, which will have only the following line: “from app import app”. This is going to be the launching point of the application and the script Flask will run first. At the moment it only imports the app from the package we made, but later we will add more things to it, mainly configurations and extensions.
  2. Next, we need to set the FLASK_APP environment variable from the command line. Run this command in your terminal : “export FLASK_APP=project.py”. This will let flask know where to find our exeuction script and start up our app.

Take a look at the screenshot below to see whats in the project.py file, what the structure of the repo is, as well as the environment variable export command. Finally, to actually run the app, I ran the following command in the terminal: “flask run”. Notice the output.

Your flask app is now being served! Flask spun up a server running in your local machine that will listen to requests on port 5000. Just click on that IP address “http://127.0.0.1:5000” and it will open a browser window showing…:

Yay! our very first Flask app! But this is boring, we want full HTML pages. Luckily Flask is great at that! The way HTML content is displayed by flask is by using something called Jinja templates. Jinja allows us to write HTML in a way where we can reuse templates and populate them with data passed into the template by our app. To make these templates, create a folder in the app folder called “templates”. By default, flask looks for templates in a folder with this exact name so make sure you spell it right! inside this template, We will simply begin to make HTML files. Lets write some HTML now!

Pretty standard HTML file. Except: notice the the double curly quotes. This is Jinja syntax. Its how we can pass variables into the HTML file so we can reuse the HTML and simply populate it with different values. Jinja will expect that when this HTML is called for display, it will be passed a dictionary called ‘user’ that has the keys ‘name’, ‘age’ and ‘favfood’ which it can then use to fill in the template. This dictionary is passed into template in the routes.py module. Lets take a look:

Notice the changes we made. First off we imported the function “render_template” which is used by the view function to …well…render the template.

Then, we added a new route and view function . Notice how we specified the URL for this route: ‘/<name>’. The <name> syntax is a way in which to allow for the user to add a string value of their choosing when they send a request to the / route, and this variable can be captured and passed into the view function. This is a powerful lawyer of abstraction that allows for us to modify the content that is returned based on user input. So in our case above, we defined a dictionary in our view function consisting of two more dictionaries, each containing data for a different person. Later on we will slice this dictionary based on the name the user appends to the URL. But

At the end of the function, we call the render_template function, pass into it the template we want to use, and specify the dictionary for the person that will be passed into an parsed by the template. This dictionary is retrieved by slicing the parent dictionary (using “users[name]” syntax) to return the sub dictionary specific the user with the name passed in into the URL, which is then passed into the user parameter. If the template had referenced a dictionary called “people” and gotten their names etc by using “people.name”, we would pass in “people=users[name]”.

So now, when we go to http://127.0.0.1:5000/john we see:

But when we go to http://127.0.0.1:5000/phill :

Amazing! Instead of writing a seperate HTML file for Phil and one for John, we only had to specify the route and write the HTML once and render_template simply filled it with the data as needed! This is the power of Jinja, and you can see how incredibly useful such a flexible framework can be. This is essentially the same principle on which social media sites like Facebook and Pinterest are built on. They could’nt possibly write HTML for every single user; instead they have templates for user profiles or news feeds or photo albums and simply populate it with each particular users unique data as requested.

Its worth keeping in mind at this stage that instead of slicing a hardcoded dictionary, we could just as easily take that user input and look up values in lets say a database. That is the ideal way, but I just wanted to keep it simple right now for the purposes of demonstration. But we should start thinking about coming up with a good way to store and manipulate user data and feed it into the templates.

This is the ‘model’ part of MVC. Right now our model is a dictionary defined in the code itself. Naturally, this is not a robust or scalable solution. If you have any experience with SQLite or even JSON based databases you might already be able to see how you can go about doing this since its really just a matter of writing the logic inside the view functions for our routes.

I have covered setting up databases in the context of Flask-RESTful API’s, which principle could be applied here. But the ideal way, as described so well in the Grinberg guide, is to use SQLAlchemy. That is a whole topic unto itself, which I think i’ll cover in my next post along with showing you how to set up forms in Flask apps to get input from the user.

Stay tuned!

--

--

Umar Khan

Just an attorney who wandered into data science and never wanted to leave.