If you’ve been looking to deploy your first web app to the cloud, this is a great place to start!
In this tutorial, I'm going to show how to make the web app and database shown in the gif above, and how to deploy it to Heroku so it can be used by anyone.
The article is divided in 3 sections:
- Creating a Flask app (web application for submitting the form)
- Setting up a Postgres database with Python (store the data from the submitted forms)
- Deploying the application to Heroku (hosting the application in the cloud so anyone can use it)
I provide a brief overview of each technology at the beginning of each section, so do not be deterred if you aren't familiar with some of these.
Technical Requirements
This guide is targeted towards beginner to intermediate programmers with some familiarity with programming and using the command line.
You will need the following to get started:
- PostgreSQL: You need to download and install Postgres on your local computer.
- Python 3.6 or newer: Python installers for different versions and OS are available for download here.
- Heroku Account: You need to create a free Heroku account if you do not already have one. This is where we will deploy the flask app and connect it to a remote Postgres database.
Once you have all the above installed, we can start by setting up our development environment.
Creating a Flask App for a Registration Form
In this section, we're going to create the Flask app shown above.
I’ve already created an example Flask app that renders a simple registration form used to collect information from a user.
Flask is one of the most popular web frameworks written in Python. The flask application I made first makes a request to the endpoints defined in the app/routes.py
file to retrieve the data that is displayed in the registration form.
It then renders the HTML pages contained in the Template
folder using the Jinja Template library.
Instead of starting from scratch, let’s make a copy of the Flask app I created by cloning the Github repo.
Open a command line tool and run the following commands:
git clone https://github.com/ToluClassics/Web_Registration_Form.git
cd web_registration_form
If you ever get lost, you can view the completed project here: Flask-Postgres App
Next we’re going to create a virtual environment for this project and install the required dependencies. A virtual environment is an isolated environment for different Python projects. They are helpful to keep packages and dependencies separate between different projects.
Depending on your computer’s operating system, run the following commands:
Windows:
$ python3 -m venv env
$ source env/scripts/activate
(env) $ pip install -r requirements.txt
MacOS and UNIX:
$ python -m venv env
$ source env/bin/activate
(env) $ pip install -r requirements.txt
To test if our environment is properly set up, let’s try launching the application by entering flask run
in the virtual environment.
(env) derekxiao@Dereks-MBP Web_Registration_Form % flask run
* 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)
Now you can enter the URL above in any browser and view the web form!
Adding input validations for the registration form
To get more familiar with the code, let’s add input validations to the form class.
We want our app to prevent users from filling out the form with the same username or email address multiple times.
With wtforms
, you can create a custom validator that is automatically added to each field by creating a method with the name validate_<field_name>
. In the app/form.py
file, we will add two methods validate_email
and validate_username
. We will query the Registrations table (we’ll create this table later) username and email entered by the user. If it returns a value , we will raise a validation error.
Open the form.py
file and first import Registrations from the models.py
file (we'll add this file later).
from app.models import Registration
And in the RegistrationForm
class add the following validation methods:
def validate_email(self, email):
user = Registration.query.filter_by(email = email.data).first()
if user is not None:
raise ValidationError('Please use a different email address')
def validate_username(self, username):
user = Registration.query.filter_by(username = username.data).first()
if user is not None:
raise ValidationError('Please use a different email address')
Now let's add in the models.py
file so we can test the input validation.
Creating a PostgreSQL Database
First we need to create the database that models.py
will connect to.
For this tutorial we'll be using a PostgreSQL database. PostgreSQL is an open source, object-relational database. And the best part, it’s completely free.
Let’s start by creating a new Postgres database to store the data from submitted registration forms. If you already have a Postgres database, feel free to jump to the next section to start connecting your Flask app to the database.
If you haven’t yet, first download and install Postgres on your computer.
Now open a new command line window and type psql
. psql
is a terminal-based interface to manage your Postgres databases.
Run the command create database [database name];
to create a new database.
Below is a list of popular psql
commands to manage your database:
-
\l
: list all available databases -
dt
: list all tables -
\d table_name
: describe a table, showing its columns, column type e.t.c -
\du
: list all users and their roles. -
\?
: get a list of all psql commands\q
: to quit psql terminal
Alternatively, you can avoid memorizing the different psql commands and use Arctype's free SQL editor that provides a modern interface for managing both Postgres and MySQL databases:
Connecting a Flask app to a Local Postgres Database
Next we'll create the database connection to our new Postgres database that will be used inside our models.py
file. To get started, there are 3 packages to install:
-
flask-sqlalchemy
: A python extension for managing databases -
flask-migrate
: For making updates to an existing database -
Pyscopg2
: A Postgresql database adapter for python
In the activated virtual environment terminal run (env) $ pip install flask-sqlalchemy flask-migrate pyscopg2
to install the packages listed above. If you hit an error installing pyscopg2
, you may need to install psycopg2-binary
instead.
The following sections I'll show how to use each package to configure and integrate our Postgres database with our Flask application. The end result will be a Flask app that is able to add new entries to a Postgres table.
Manage Postgres databases from Python with SQLAlchemy
SQLAlchemy is a library that provides a way to seamlessly integrate python programs and databases. We will use SQLAlchemy as an Object Relational Mapper to convert python classes to tables in our Postgres database.
Flask-SQLAlchemy automatically translates the created models to the syntax of any database (Postgres in our case).
To interact with our database from the application, We need to add the following configuration variables to the config file:
-
SQLALCHEMY_DATABASE_URI
: this is the connection string that tells our Flask app which database to connect to. The usual form of the postgres database connection string ispostgresql://localhost/[YOUR_DATABASE_NAME]
. If your Postgres user has a password, you will need to use a different URI variant. -
SQLALCHEMY_TRACK_MODIFICATIONS
: We set this toFalse
so we do not get a warning from flask every time we make a change to the application.
To make the above changes, open the config.py
file and add the following variables to the Config
class:
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI') or \
'postgresql://localhost/[YOUR_DATABASE_NAME]'
SQLALCHEMY_TRACK_MODIFICATIONS = False
In the next session, we'll use the flask-migrate
package to seamlessly handle changes to our database structure.
Setting up Flask-Migrate to Manage Database Structures
As we scale our application, we may need to make structural changes to our tables without losing all the data already in the database. Flask-Migrate is a python extension that handles SQLAlchemy database migrations automatically using Alembic. It also supports multiple database migrations and other functionalities.
Now, we will add a database object that represents our database and also create an instance of the migration class to handle database migrations.
Open the app/ __init__.py
and first import the flask-migrate and SQLAlchemy packages:
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
Then add the following variables:
db = SQLAlchemy(app) ## Create DB object
migrate = Migrate(app,db) ## Create migration object
Set up the PostgreSQL database model
Now we're finally ready to create the models.py
file to set up our database model. Database models are used to represent tables and their structures in the database; they determine the schema of the table.
models.py
will define the structure of our tables and other necessary table information. We need to create a model (Class) whose attributes are the same as the data fields we intend to store in the database tables.
Inside the app
directory, create a new file called models.py
and first import the db instance that we created in the previous section: from app import db
.
Then create a class with the attributes for each data field in the registration form:
class Registration(db.Model):
id = db.Column(db.Integer, primary_key = True)
first_name = db.Column(db.String(64))
last_name = db.Column(db.String(64))
username = db.Column(db.String(64))
company = db.Column(db.String(64))
contact_no = db.Column(db.String(64))
email = db.Column(db.String(120), index=True, unique=True)
def __repr__ (self):
return '<User {}>'.format(self.username)
The last step is importing the model in the app\ __init__.py
file: from app import models
.
If you are working with your own database, we've created a free tool to design database schemas.
Creating a new Registrations table in Postgres using Flask
Next, we will instantiate the database from the command line by running flask db init
in the virtual environment.
First ensure that your FLASK_APP
environment variable is set before you run this command. You can run the following commands to check:
(env) $ python
Python 3.8.2 (default, Dec 21 2020, 15:06:04)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> print(os.environ['FLASK_APP'])
app.py
>>> quit()
After you run flask db init
you should see the following output:
(env) $ flask db init
Creating directory /Users/mac/Desktop/Web_Registration_Form/migrations ... done
Creating directory /Users/mac/Desktop/Web_Registration_Form/migrations/versions ... done
Generating /Users/mac/Desktop/Web_Registration_Form/migrations/script.py.mako ... done
Generating /Users/mac/Desktop/Web_Registration_Form/migrations/env.py ... done
Generating /Users/mac/Desktop/Web_Registration_Form/migrations/README ... done
Generating /Users/mac/Desktop/Web_Registration_Form/migrations/alembic.ini ... done
Please edit configuration/connection/logging settings in
'/Users/mac/Desktop/Web_Registration_Form/migrations/alembic.ini' before proceeding.
From the command logs, we can see that a migrations folder is created in our application. This folder contains files that are needed to migrate tables and update table schemas on our database.
Now that we have a migrations repository, it’s time to migrate the Registration table to the database using the flask-migrate
extension.
Ensure that your Postgres server is up, then run the flask db migrate
command to automatically migrate our SQLAlchemy database to the Postgres database that we assigned earlier with the URI in the config file.
(env) $ flask db migrate -m "registrations table"
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'registration'
INFO [alembic.autogenerate.compare] Detected added index 'ix_registration_email' on '['email']'
Generating /Users/mac/Desktop/Web_Registration_Form/migrations/versions/eccfa5d8a3f6_registrations_table.py ... done
flask db migrate
does not make any changes to the database, it only generates the migration script. To make the changes, we use the flask db upgrade
command. You can also revert the changes by using flask db downgrade
.
(env) $ flask db upgrade
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> eccfa5d8a3f6, registrations table
Now we can open Arctype and check if the table was successfully migrated to the local Postgres database
Inserting Data From a Flask App in Postgres
In this section, we'll update our route function to add the data collected from the webpage to the website.
First, we will update our imports by including our database instance and table model in the app\routes.py
file:
from app.models import Registration
from app import db
from flask import redirect, url_for
In the route function, we will create an instance of the Registration
class and update it with information collected from the form. We then proceed to add and commit the instance to the database.
Add the following if statement inside the index()
function in routes.py
:
if form.validate_on_submit():
reg_form = Registration(username=form.username.data,email=form.email.data, first_name=form.first_name.data,last_name=form.last_name.data, company=form.company.data,contact_no=form.contact_no.data)
db.session.add(reg_form)
db.session.commit()
return redirect(url_for('index'))
Testing if the Flask App is Inserting Data in Postgres
Let's test our application locally one more time before deploying to Heroku:
(env) $ flask run
* 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)
Navigate to http://127.0.0.1:5000/ and submit the form.
After submitting the form, you can check that a new entry was added to your database by checking the Registrations table in Arctype:
Deploying the Flask app and Postgres Database to Heroku
Now that we have tested our application locally, it's time to deploy the application and our Postgres database to Heroku so we can access it from anywhere.
The first step is downloading and installing the Heroku CLI.
Then we can log into Heroku from the command line with: Heroku login
Once we're logged in, we can create a new app on Heroku with by running: Heroku create [app-name]
. Heroku apps are in a global namespace, therefore you need to choose a unique name for your application. If you do not specify a name for your application, Heroku will generate a random name for your application.
(env) $ Heroku create arctype-registration-app
Creating ⬢ arctype-registration-app... done
https://arctype-registration-app.herokuapp.com/ | https://git.heroku.com/arctype-registration-app.git
To proceed with development, we need to update our requirements.txt
file and create a Procfile
in our root directory. The Procfile
is used to declare the commands run by the app on Heroku.
Next, we need to install gunicorn
which is a python server needed to run the application on Heroku. In the activated python environment, run pip install gunicorn
to install the gunicorn
package.
Run pip freeze > requirements.txt
to update the requirements file. The procfile
defines processes based using the following format <process type>: <command>
. Since our application contains a web server (gunicorn), the process type is web and the command will launch the gunicorn server. Therefore, we need to run the command below on the terminal to create the Procfile:
echo web: gunicorn app:app > Procfile
Heroku has differentservice plans for its postgresql offering. Choosing a plan for your application depends on the characteristics of your application and its bandwidth for service downtimes. In this tutorial we will use the hobby-dev plan, which is free and serves the purpose we need it for.
Now, we will create a hobby-dev postgres database for our application using the heroku addons:create heroku-postgresql:hobby-dev --app app-name
command:
(env) $ heroku addons:create heroku-postgresql:hobby-dev --app arctype-registration-app
Creating heroku-postgresql:hobby-dev on ⬢ arctype-registration-app... free
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Created postgresql-slippery-96960 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation
More information on working with postgres databases can be found here.
Now that we have created a remote postgres database for our application on Heroku, we need to update the SQLALCHEMY_DATABASE_URI
variable in the config.py
file with the new database URI. To retrieve the remote database URI, we use the heroku config --app app-name
command.
Once the URI is updated, the final step is deploying our application to Heroku's servers.
First, we will commit all our files and push to the heroku master branch. Run git add .
and git commit -m “heroku commit”
, then git push heroku main
to deploy to Heroku.
Your app is now live at https://your-app-name.herokuapp.com
!
Migrating Tables from a Local Postgres Database to Heroku
The last step is migrating the Registrations table that we created in our local Postgres database to the new Heroku database instance. We can do this by running db create_all()
from the heroku python terminal:
(env) $ heroku run python
Running python on ⬢ arctype-registration-app... up, run.9023 (Free)
Python 3.6.12 (default, Sep 29 2020, 17:50:28)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from app import db
>>> db.create_all()
To check if the Registrations table was successfully created, connect to the Heroku database from Arctype and you should see the Registrations table.
Congratulations!
You are now the proud owner of a web app that anyone with internet access can use, from anywhere in the world. Lets zoom out and review what we covered:
- How a Flask app works
- Creating a Postgres database
- Creating a database model in Python using SQLAlchemy
- Migrating a database in Python using flask-migrate
- Inserting data into a Postgres database from a Flask app
- Deploying a Flask app and Postgres database to Heroku
Postgres is a powerful database that is used by large tech companies across the world. Arctype is a free SQL editor that makes working with databases easier. Try Arctype for free today.
Top comments (0)