How to use GeoDjango

GeoDjango tutorial

Hey there! Some links on this page may be affiliate links which means that, if you choose to make a purchase, I may earn a small commission at no extra cost to you. I greatly appreciate your support!

In this tutorial, you will learn how to import a shapefile into a PostgreSQL database and display map data in the Django admin console.

The system I used was Ubuntu 22.10 on DigitalOcean. Here’s $200 free DigitalOcean credits if you’d like to follow along.

This blog post accompanies the following video tutorial.

YouTube video

1. Install PostgreSQL

First, update system packages and install the PostGIS package which includes PostgreSQL among other necessary dependencies.

sudo apt update
sudo apt upgrade
sudo apt install postgis

2. Setup PostgreSQL Database

Let’s switch to the postgres user and create a database called gitdb. Then login to the Postgres console so we can issue database commands.

sudo su - postgres
createdb gisdb
psql gisdb

Create a database user called george and password with appropriate privileges and settings.

CREATE EXTENSION postgis;
CREATE USER george WITH PASSWORD 'geographyisfun';
ALTER ROLE george SET client_encoding TO 'utf8';
ALTER ROLE george SET default_transaction_isolation TO 'read committed';
ALTER ROLE george SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE gisdb TO george;
exit

3. Create a New User

Rather than using the root user, let’s create another user.

exit
adduser tony
usermod -aG sudo tony
su - tony

4. Install Python

Install Django, Python, and other necessary packages so Python can communicate with the PostgreSQL database.

sudo apt install python3-django python3-psycopg2

5. Setup Django

Start a new Django project called gis and a new Django app called world.

django-admin startproject gis
cd gis
python3 manage.py startapp world

Point Django to the PostgreSQL database. Edit the file at world/settings.py.

...
DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'gisdb',
        'USER': 'george',
        'PASSWORD': 'geographyisfun',
        'HOST': 'localhost',
    },
}
...

Also in world/settings.py, add the django.contrib.gis app and world app to INSTALLED_APPS.

...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.gis',
    'world',
]
...

6. Get Shapefile from Natural Earth Data

We will be using a free shapefile from naturalearthdata.com that contains 209 sovereign countries at 1:10m scale.

In the world directory, create a maps subdirectory. Then use the wget command to download the zip file from the Natural Earth website.

cd world
mkdir maps
cd maps
wget https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_sovereignty.zip

We need to install the unzip package first before unzipping the zip file.

sudo apt install unzip
unzip ne_10m_admin_0_sovereignty.zip
cd ../..

In the zip file, you’ll find a bunch of files including the shapefile that we’re interested in.

7. Import Shapefile to GeoDjango

We can use the ogrinspect command that is part of GeoDjango to easily define a Django model called Country to represent the shapefile data. The null option is necessary since some fields in the shapefile are empty.

python3 manage.py ogrinspect world/maps/ne_10m_admin_0_sovereignty.shp Country --mapping --multi --name-field name --null true

This command will print out the following two sections.

The first section is the Django model definition. Paste this section into world/models.py replacing everything.

# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models

class Country(models.Model):
    featurecla = models.CharField(max_length=19, null=True)
    ...
    geom = models.MultiPolygonField()

    def __str__(self): return self.name

The second section is a Python dictionary that maps the model fields to the PostgreSQL database.

# Auto-generated 'LayerMapping' dictionary for Country model
country_mapping = {
    'featurecla': 'featurcla',
    ...
    'geom': 'MULTIPOLYGON',
}

Create a new file called world/load.py and paste the second section in there with the follow additional modifications.

from pathlib import Path
from django.contrib.gis.utils import LayerMapping
from .models import Country

country_mapping = {
    'featurecla': 'featurcla',
    ...
    'geom': 'MULTIPOLYGON',
}

country_shp = Path(__file__).resolve().parent / 'maps' / 'ne_10m_admin_0_sovereignty.shp'

def run(verbose=True):
    lm = LayerMapping(Country, country_shp, country_mapping, transform=False)
    lm.save(strict=True, verbose=verbose)

For reference, here is the Django documentation for LayerMapping.

Now let’s tell the Django database about our model definition.

python3 manage.py makemigrations
python3 manage.py migrate

Then we can finally load the shapefile data into the database with the world/load.py script.

python3 manage.py shell
from world import load
load.run()

8. Register Django Model in Admin Site

Django comes with a fantastic admin site that requires no coding. We simply need to register the Country model with the admin site and create a user to login to the site.

Modify world/admin.py like this to register the Country model with the Django admin site.

from django.contrib.gis import admin
from .models import Country

admin.site.register(Country)

Create a Django user that can access the admin site.

python3 manage.py createsuperuser

9. View the Map Data in the Django Admin Site

Run the Django development server.

python3 manage.py runserver 0.0.0.0:8000

In a web browser,  go to http://localhost:8000/admin (or http://YOUR_IP_ADDRESS:8000/admin if you’re on a remote server). Login with your Django user that you just created.

When you click on the “Countrys” link and pick any of the 209 countries in the list, you will see all the shapefile metadata including a map of the country like this.

Map of Singapore in the Django admin site

Next, learn how to display map data on a web page with Leaflet and GeoJSON.

Facebook
Twitter
Pinterest
LinkedIn
Reddit

Meet Tony

Tony Teaches Tech headshot

With a strong background in computer science and enterprise web development, Tony is determined to demystify the web. Discover why Tony quit his job to pursue this mission. You can join the Tony Teaches Tech community here.

Leave a Reply

Your email address will not be published. Required fields are marked *