Skip to content

PostgreSQL Tutorial

This tutorial demonstrates how to integrate a Postgres database with a Dash app. First, we'll set up a local Postgres database for testing and then provision a Postgres database through Heroku. Credit to Charming Data for his tutorial and inspiration for this tutorial.

1. Install Postgres

Visit the Postgres website and download the right version of Postgres for your operating system (note that you may need to use a different browser if the download does not start automatically).

Once the install begins, follow these instructions to set up Postgres on your local machine. Uncheck 'Stack Builder' when prompted, you won't need it. Make sure you write down the superuser password you set up!

This installation will automatically install pgAdmin, the default database management client for Postgres, and psql, a command line interface for Postgres. (If you're following the instructions linked above to verify your Postgres install, note that the password will not display on screen when you type it for security reasons).

2. Configure a local server

A local database will be used during development to test the app before we deploy to Heroku.

Open pgAdmin (note pgAdmin opens in your browser). When you first open pgAdmin, you'll need to set a master password (for simplicity, I'd recommend using the same password you used to set up Postgres).

Select 'Add New Server' (under Dashboard). Configure the new server following the images below. You may change the name of the server if you wish. Provide the password used to install Postgres as the password here.

img

3. Set up a local database

In the left sidebar, right-click on Databases undermy_local_server and select Create> Database.... Call the database test and save.

4. Create a table

In the left sidebar, navigate to my_local_server> Databases> test> Schemas> Tables to access the tables associated with the database. Since this is a new database, we'll need to create a table. Note, if you called your database something other than test, you should navigate to your database in the tree.

Right-click Tables and select Create> Table.... Configure the new table following the images below. You may change the name of the table if you wish, but the name of the table will be used in our code so don't forget it. Use the 'plus' sign on the right to add columns.

If you have an existing CSV that you would like to import, make sure that the column names you create match exactly the column names in the CSV.

img

If you need help figuring out which data type to use, review the guidance here. The most common types are 'text', 'int', 'real', and 'date'.

5. Populate table

If you have an existing CSV, you can import it by right-clicking on the table in the left sidebar and selecting 'Import/Export'. Configure as shown below.

img

Otherwise, select 'View/Edit Data' to input data manually.

I'll be using a CSV like the one below to import data.

Code Project Practice_Area
1001 MI2 International
1002 LAC ESSC International

After importing, select 'View/Edit Data' from the my_table context menu (right-click) to confirm successful import.

6. Connect to the local database in the app

The code below illustrates how to connect to the database on your local server in a simple Dash app.

We'll use SQLAlchemy through Flask (Dash is built on Flask) to connect to the database.

# See Charming Data's tutorials at https://www.youtube.com/channel/UCqBFsuAz41sqWcFjZkqmJqQ/featured
import dash
from dash.dependencies import Input, Output, State
import dash_table
import dash_core_components as dcc
import dash_html_components as html

import pandas as pd
import os

from flask_sqlalchemy import SQLAlchemy
from flask import Flask

# app requires "pip install psycopg2" as well

server = Flask(__name__)
app = dash.Dash(__name__, server=server, suppress_callback_exceptions=True)
app.server.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# for your home PostgreSQL test table, replace <password>
# Format: "postgresql://<username>:<password>@<host name/address>/<database name>"
app.server.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://postgres:<password>@localhost/test"

db = SQLAlchemy(app.server)


# ------------------------------------------------------------------------------------------------

app.layout = html.Div([
    html.Div(id='postgres_datatable'),
    dcc.Interval(id='interval_pg', interval=86400000*7, n_intervals=0)
    ]
)


# ------------------------------------------------------------------------------------------------


@app.callback(Output('postgres_datatable', 'children'),
              [Input('interval_pg', 'n_intervals')])
def populate_datatable(n_intervals):
    df = pd.read_sql_table('my_table', con=db.engine)
    return [
        dash_table.DataTable(
            id='our-table',
            columns=[{
                         'name': str(x),
                         'id': str(x),
                         'deletable': False,
                     } 
                     for x in df.columns],
            data=df.to_dict('records'),
            editable=True,
            row_deletable=True,
            filter_action="native",
            sort_action="native",  # give user capability to sort columns
            sort_mode="single",  # sort across 'multi' or 'single' columns
            page_action='none',  # render all of the data at once. No paging.
            style_table={'height': '300px', 'overflowY': 'auto'},
            style_cell={'textAlign': 'left', 'minWidth': '100px', 'width': '100px', 'maxWidth': '100px'},
            style_cell_conditional=[
                {
                    'if': {'column_id': c},
                    'textAlign': 'right'
                } for c in ['Price', 'Sales']
            ]

        ),
    ]


if __name__ == '__main__':
    app.run_server(debug=True)

Note how we set up a server using Flask, configured the SQLAlchemy Database URI connection string, and instantiated a database connection object db = SQLAlchemy(app.server), highlighted below.

# code specific to SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
from flask import Flask

server = Flask(__name__)
app = dash.Dash(__name__, server=server, suppress_callback_exceptions=True)
app.server.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app.server.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://postgres:<password>@localhost/test"

db = SQLAlchemy(app.server)

To read in the table, we use pandas' pd.read_sql_table, passing db.engine as the connection object.

# code specific to reading sql tables
import pandas as pd

df = pd.read_sql_table('my_table', con=db.engine)

7. Deploy app to Heroku and provision a database

Next, we'll deploy the app to Heroku and provision a database using the Heroku Postgres add-on. If you need guidance on deploying to Heroku, see our tutorial.

Open the app at Heroku.com and click on 'Resources' to provision a Postgres database. Search for 'postgres', select 'Heroku Postgres', and click 'Provision' (you can use the Free version for this demo).

7. Connect to the remote database in pgAdmin

In 'Resources' you should see the add-on you provisioned. Click on it, click 'Settings', and 'View Credentials'. You'll need this info to connect to the server through pgAdmin on your computer, and to use this database in your app.

Open pgAdmin and in the left sidebar, right-click on 'Servers' and select 'Create Server'. By copying and pasting the credentials from Heroku, provision the server. In the images below, I've typed the corresponding field from Heroku to use in pgAdmin. The password should also be copied over.

img

You should now be able to find your database in the list of databases within the server you just set up. There will be hundreds of databases in that list, use Ctrl+F and search for the database name to find it quickly (it will be colored gold).

Note that the credentials you used may be 'rotated' (changed) by Heroku. This won't affect your app, but it will affect your connection through pgAdmin. If you can't find your database in pgAdmin, just repeat this step.

Repeat steps 4 and 5 to create and populate tables in your new database.

8. Connect your app to your remote database

Now you're ready to connect your app to your remote database!

You'll want to keep your database credentials out of git and GitHub, so we'll use an environment variable. Helpfully, Heroku creates a DATABASE_URL environment variable for you when provisioning the database. You can check this at your app page in Heroku: select 'Settings' and click 'Reveal Config Vars'.

Simply swap out your local connection string with the database URI provided for you Heroku database using the environment variable created by Heroku (you can find the URI listed in the database credentials under Settings).

import os

app.server.config["SQLALCHEMY_DATABASE_URI"] = os.environ['DATABASE_URL']

Note you will need to install psycopg2 in your environment if you haven't already. Update your requirements.txt and re-deploy the app with the new connection details.

If you want to test your app locally, you can set up a database_uri.json file in your secrets/ directory to store the URI. Here's what that file would look like:

{
    "DATABASE_URI": "<DATABASE URI>"
}

You can use a try/except block to handle connections:

import json

try:
    app.server.config["SQLALCHEMY_DATABASE_URI"] = os.environ['DATABASE_URL']
except:
    with open ('secrets/database_uri.json') as f:
        app.server.config["SQLALCHEMY_DATABASE_URI"] = json.load(f).get("DATABASE_URI")

For more info on Heroku Postgres, read the docs.