Let's start our design of the DISTAL application by thinking about the various pieces of data it will require:
Fortunately, this data is readily available:
Looking at these data sources, we can start to design the database schema for the DISTAL system, which will look like this:

While this is very simple, it's enough to get us started. Let's use this schema to create our spatial database and set up our database schema. This involves the following steps:
createdb distal
createuser -P distal_user
You'll be asked to enter a password for this new user. Make sure you remember the password you enter.
psql distal
distal_user user to access the distal database by entering the following:
GRANT ALL PRIVILEGES ON DATABASE distal TO distal_user;
CREATE EXTENSION postgis;
You can now exit the Postgres command-line client by typing \q and pressing Return. We're next going to write a Python script to create our various database tables. Before we can do this, though, we're going to need somewhere to store the source code to the DISTAL system. Create a new directory called DISTAL in a convenient location. Inside this directory, create a new Python script named create_db.py, and enter the following into this file:
import psycopg2
connection = psycopg2.connect(database="distal",
user="distal_user",
password="...")
cursor = connection.cursor()
cursor.execute("DROP TABLE IF EXISTS countries")
cursor.execute("""
CREATE TABLE countries (
id SERIAL,
name VARCHAR(255),
outline GEOMETRY(GEOMETRY, 4326),
PRIMARY KEY (id))
""")
cursor.execute("""
CREATE INDEX countryIndex ON countries
USING GIST(outline)
""")
cursor.execute("DROP TABLE IF EXISTS shorelines")
cursor.execute("""
CREATE TABLE shorelines (
id SERIAL,
level INTEGER,
outline GEOMETRY(GEOMETRY, 4326),
PRIMARY KEY (id))
""")
cursor.execute("""
CREATE INDEX shorelineIndex ON shorelines
USING GIST(outline)
""")
cursor.execute("DROP TABLE IF EXISTS places")
cursor.execute("""
CREATE TABLE places (
id SERIAL,
name VARCHAR(255),
position GEOGRAPHY(POINT, 4326),
PRIMARY KEY (id))
""")
cursor.execute("""
CREATE INDEX placeIndex ON places
USING GIST(position)
""")
connection.commit()Notice that we define the outlines to have a column type of GEOMETRY(GEOMETRY, 4326). The first occurrence of the word GEOMETRY defines the column type; we are using geometry columns rather than geography columns to avoid problems with calculating bounding boxes and other values, which unfortunately doesn't work with geography columns. Within the parentheses, the second occurrence of the word GEOMETRY tells PostGIS that we can hold any type of geometry value we want; this allows us to store either a Polygon or a MultiPolygon for the outline, depending on the type of outline we want to store. We're also following the recommended best practice of specifying the spatial reference ID (SRID) value for our data. We'll use the WGS84 datum and unprojected lat/long coordinates for our data, which corresponds to an SRID value of 4326.
For the places table, we are using GEOGRAPHY(POINT, 4326), which does use the GEOGRAPHY column type so that we can perform accurate distance-based queries within the database. This time, we're constraining the place to hold a single Point value, and we again use the SRID value of 4326 for this data.
Go ahead and run the create_db.py program; it should run without any errors, leaving you with a properly set up database schema.