Create and Deploy a Simple Web Application with Flask and Heroku | by Naveen Venkatesan | Jan, 2021

[ad_1]


Say you’ve written a really cool script in Python to do some interesting data analysis and now you want to demonstrate it to others. Chances are, sending over a .py file and asking others to run it, or demonstrating yourself running it on the command line won’t have the same grasp as a nicely packaged and polished web application. By using the Python package flask, we can create one of these interactive applications fairly quickly. In this article, I will make a simple web application that displays the number of times the homepage was visited and deploy it on Heroku to share with others.

Note — All screenshots below are taken by the author.

The easiest way to deploy our project downstream is to create a new repository on GitHub, where all of our files will live. So I started by creating a new repo at github.com/n-venkatesan/sample-webapp and cloning it to my local computer. When creating the repository, you have the option of initializing with a .gitignore file — I would recommend choosing Python from the dropdown menu to avoid unnecessary files being checked into Git.

> git clone https://github.com/n-venkatesan/sample-webapp> cd sample-webapp/

Now all we need to do is create a file called templates where our HTML file will live:

> mkdir templates

Done with setting up the folder structure!

We want to start with a new clean slate for our development so that we only install the dependencies that are absolutely necessary for our application — this will be especially important later when we deploy our web app.

> python3 -m venv venv> source venv/bin/activateIf you see the name of the virtual environment (venv) before the command prompt, you have successfully activated the new environment(venv) > Success!

We now need to install the dependencies necessary for our app, which will be flask and gunicorn, which is a Python web server interface that we need to run our application.

(venv) > pip install flask gunicorn

Cool — now we can start creating our app!

In our templates/ directory, create a new file called index.html. This will be the page that shows when we try to access our web application. To see what the rendered HTML looks like, you can open the file in a web browser. This tutorial assumes that you have a very basic understanding of HTML and CSS, but there are plenty of resources like W3School that can help you get up to speed.

Our page will just consist of two elements, a title that says Welcome! and a paragraph below that says This site has been visited n times., where n is the actual number of times the website has been visited up to that point. We will nest both of these elements inside of a <div> block in order to do some CSS styling later on. The <br> tag signifies a line break between the title and paragraph.

<div>
<h1>Welcome!</h1><br>
<p>This site has been visited {{ count }} times.</p>
</div>

The only thing about the above HTML block that may appear new is the {{ count }} text in the paragraph block. The double curly braces ({{ }}) mean that you are running Python code within that block — so we are referencing the value of the variable count, which we will pass to the HTML template later on.

In its current state, our page looks like this:

Pretty basic — let’s add some formatting! First, let’s choose a different font for the text. I like to go to Google Fonts, which has a wide array of free fonts you can use — for this app, I chose a font called Rubik. Next to each of the font weights, there is a button that says “Select this style” — clicking at least one of these will open up a window on the right that has code you can copy/paste into your HTML to have access to that font! I just chose the Regular 400 font weight, and got the following code which I added to the top of my index.html file:

<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Rubik&display=swap" rel="stylesheet">

Now we can style the page using CSS — we start by creating a style tag in index.html and putting all of our CSS code into here. We are going to make the font of all text on our page Rubik, which we can do by changing the attribute of *, which corresponds to all elements. Additionally, we will move all the content down by 50 pixels from the top the page, make the title red, and change the font sizes of both the title and paragraph sections. I’ve added this code right below the links for the fonts but before any of the actual page content.

<style>
* {
font-family: "Rubik", "sans-serif";
}
div {
text-align: center;
margin-top: 50px;
}
h1 {
color: red;
font-size: 40pt;
}
p {
font-size: 24pt;
}
</style>

Looks much better! Now, we can add the Python backend that will run our application!

In our main project folder, we can create a file called app.py which will be the backend for our web application. The first thing we need to do is import the required packages.

from flask import Flask, render_template

Flask is what we will use to instantiate our application, and render_template is what we will use to connect the HTML we wrote above to our application.

We must now create our app, which I will store in a variable called app:

app = Flask(__name__)

Now, we need to deal with routing — a route is a URL pattern, i.e. the base URL of your website would have the route of /, whereas another route within your website may have the path /route_path. Since our application only has one page, we will only need to write a function for the / route. To specify the route, we use a decorator above our function with the form @app.route(route_path). The function currently does nothing, as we just added a pass to the body.

@app.route("/")
def index():
pass

Our function is going to need to do 4 things:

  1. Load in a file called count.txt which we will use to keep track of the current count of the number of visitors to the site
  2. Increment the count by 1
  3. Overwrite the contents of count.txt with the new value of the count
  4. Render the HTML we wrote earlier with the value of the count variable inserted.

Loading current count

Let’s first create a file called count.txt in the main project folder with just 0 as the only character (since we currently have no visitors).

(venv) > less count.txt0
count.txt (END)

Now in our function index() we can add the following code to read in the current value of count:

@app.route("/")
def index():
# Load current count
f = open("count.txt", "r")
count = int(f.read())
f.close()

We are opening the file count.txt in read mode (r), reading the contents of the file with f.read(), and casting the value to the integer with int(). Finally, we close the file with f.close().

Incrementing the count

We can do this in one line with the following:

@app.route("/")
def index():
# Load current count
f = open("count.txt", "r")
count = int(f.read())
f.close()
# Increment the count
count += 1

Overwriting the count value

Similar to what we did when reading in the count, we now open the file count.txt in overwrite mode (w) and write the value of the new count (cast as a string with str()) to the file, before closing the file again.

@app.route("/")
def index():
# Load current count
f = open("count.txt", "r")
count = int(f.read())
f.close()
# Increment the count
count += 1
# Overwrite the count
f = open("count.txt", "w")
f.write(str(count))
f.close()

Rendering the HTML

Now that we have the count incrementing every time we route to /, we need to render the HTML we wrote earlier, but with the value of count inserted. Remember how we had to create our index.html file inside a subfolder called templates? This is because flask has a function called render_template() which automatically looks into this folder, and can take keyword arguments corresponding to variables that are referenced in the HTML file! In this case, we refer to the value of a variable called count in our HTML by writing {{ count }}. So, by passing the value using render_template() we can reference this in our HTML.

@app.route("/")
def index():
# Load current count
f = open("count.txt", "r")
count = int(f.read())
f.close()
# Increment the count
count += 1
# Overwrite the count
f = open("count.txt", "w")
f.write(str(count))
f.close()
# Render HTML with count variable
return render_template("index.html", count=count)

We are almost done! To run our application, we need to add the following lines to our app.py code:

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

The code above starts our application web server when we call the Python script from the command line. So now, to run our app:

(venv) > python app.py* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

As revealed in the output, our web server is running at 127.0.0.1:5000, which can also be accessed with localhost:5000. Navigate to this URL and you will find:

Woohoo! Since the current value of count is also stored in the count.txt file, even if you stop and restart the web server, you will have an accurate total count value!

Heroku is a service that allows you to deploy this Python web application so that anyone with the link will be able to use it. The first thing you should do is make a free account on Heroku. Once you have created an account, from your dashboard, click the button that says “Create New App”. From here, give your application a name and click “Create app”.

Before we can deploy our web application, we need to add a couple more files for Heroku to recognize. The first is a file called requirements.txt and is essentially a list of Python dependencies that Heroku server needs to install in order to run your app. Thankfully, by working in a virtual environment, you had already installed the needed dependencies. So creating our requirements.txt file is as simple as:

(venv) > pip freeze > requirements.txt(venv) > less requirements.txtclick==7.1.2
Flask==1.1.2
gunicorn==20.0.4
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
Werkzeug==1.0.1
requirements.txt (END)

Those are all the dependencies that installed earlier when you ran pip install flask gunicorn.

The second file is called the Procfile and it is the list of instructions to Heroku on how to run your application. This file will be a one-liner that specifies two things:

  1. The web server interface to use (gunicorn)
  2. The name of the app (app)
web: gunicorn app:app

Now that you have the requirements.txt and Procfile created, we can check all of this into our GitHub repo:

(venv) > git add .
(venv) > git commit -m "Added web application files"
(venv) > git push origin main

Now from our application dashboard, we can choose to connect to GitHub by pressing the associated button. We will then be redirected to log into GitHub and give permission for use by Heroku. We can then choose the repository that is associated with our project.

Connecting your Heroku application to Github

Finally, we have two options:

  1. Automatic deploys — this will result in the application re-deploying every time there is a new push to the repository on the specified branch.
  2. Manual deploy — you can manually deploy the application from the specified branch by clicking the button
Automatic vs. manual application deployment

We will deploy manually for now — after clicking the deploy button, you will see the build log for a couple minutes, after which you will see if your app was successfully deployed.

You can click “View App” to see your awesome web application! You can see the results of this tutorial here. Keep in mind that if your app doesn’t receive a lot of traffic, it goes into a hibernation mode after a few hours, so the next time you try to access it, it may take a few seconds to spin up. Additionally, the Heroku machines are restarted once per day, so you will lose changes to the local filesystem. If you wanted the count.txt file to be unaffected, you should place it on a cloud file storage system like Amazon S3 and make requests using your application. For this example, however, I wanted to leave it simple, so the count will reset every once in a while as the machines are restarted.

All the code from this article can be found at this repository.

Thank you for reading! You can see some of my work at my personal GitHub page. I appreciate any feedback, and you can find me on Twitter and connect with me on LinkedIn for more updates and articles.



Read More …

[ad_2]


Write a comment