Using GeoDjango to filter by Points

Just recently I found myself playing with GeoDjango , I’ve been using it on both a Ubuntu 14.04 cloud server and a Macbook Pro (OS X El Capitan).

GeoDjango allows us to query by geographic points directly on the data model. We are then able to extend the model, and add a custom method to search by zipcode.

Using the Django shell we can easily check data in our favorite interpreter :

$ ./ shell

In [1]: from hub.models import Vendor

In [2]: Vendor.get_vendors(zipcode='78664', miles=5)
Out[2]: [<Vendor: Starbucks>]

In [3]: Vendor.get_vendors(zipcode='78664', miles=10)
Out[3]: [<Vendor: Starbucks>, <Vendor: Starbucks>,
<Vendor: Starbucks>, <Vendor: Starbucks>,
<Vendor: Starbucks>, <Vendor: Starbucks>, <Vendor: Starbucks>]

It’s then pretty easy to take that data and present it on a Google Map ( using the Django application’s views and templates ):

If you find any of this exciting; read on, I’m going to go over setting the environment up from scratch ( using a Macbook as the development environment).



It is a good idea to add ’s bin path to your $PATH .

You should run the following command (changing the version to match your install), and add it to the bottom of your ~/.bash_profile :

export PATH=$PATH:/Applications/

Next lets create our PostgreSQL database, and enable the GIS extension.

Start the OSX application. Next click the elephant from your upper task bar, and select Open psql .

nessy=# create database geoapp;

nessy=# \c geoapp
You are now connected to database "geoapp" as user "nessy".

geoapp=# CREATE EXTENSION postgis;

You can now close the psql shell.

Next lets install Django into a virtualenv

# create and change to new app directory
mkdir ~/geoapp && cd ~/geoapp/

# create a fresh virtual environment
virtualenv env

# activate the virtual environment
source env/bin/activate

# install Django inside the virtual environment
pip install Django

To use PostgreSQL with Python we will need the adapter installed, be sure you added’s bin path to your $PATH:

pip install psycopg2

GeoDjango requires the geos server to be available, we can install this with homebrew :

brew install geos

We are now ready to create the Django project and application.

# create a new project using Django admin tool
django-admin startproject geoproject

# change to the newly created project directory
cd geoproject/

# create a new application
./ startapp hub

Now you need to configure your Django application to use PostgreSQL and GIS, open geoproject/ with your favorite text editor.

vim geoproject/

Append django.contrib.gis and hub to your INSTALLED_APPS:


Next find the DATABASES portion and set it to the postgis engine:

    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'geoapp',
        'PASSWORD': '',
        'HOST': 'localhost',
        'PORT': ''

The next step will be to create our model using GIS points, add the following to hub/ :

from django.contrib.gis.db import models
from django.contrib.gis.geos import Point, fromstr
from django.contrib.gis.measure import D

class Vendor(models.Model):

    def __unicode__(self):
        return unicode(

    def save(self, *args, **kwargs):
        if self.latitude and self.longitude:
            self.location = Point(float(self.longitude), float(self.latitude))
        super(Vendor, self).save(*args, **kwargs)

    name = models.CharField(max_length=100)
    longitude = models.FloatField()
    latitude = models.FloatField()
    location = models.PointField(blank=True, null=True)

You will also want to add this model to the admin page, so update hub/ :

from django.contrib import admin

from hub.models import Vendor

class VendorAdmin(admin.ModelAdmin):
    list_display = ('name', 'longitude', 'latitude')
    exclude = ('location',), VendorAdmin)

At this point you are ready to create the database tables, use the provided script:

./ syncdb

I’m going to now jump into the Django shell to add data, but this can also be done using the admin ( ):

./ shell

In [1]: from hub.models import Vendor

In [2]: Vendor.objects.create(longitude=-97.677580, latitude=30.483176,
   ...: name='Starbucks')
Out[2]: <Vendor: Starbucks>

In [3]: Vendor.objects.create(longitude=-97.709085, latitude=30.518423,
  ...: name='Starbucks')
Out[3]: <Vendor: Starbucks>

In [4]: Vendor.objects.create(longitude=-97.658976, latitude=30.481517,
   ...: name='Starbucks')
Out[4]: <Vendor: Starbucks>

In [5]: Vendor.objects.create(longitude=-97.654141, latitude=30.494810,
   ...: name='Starbucks')
Out[5]: <Vendor: Starbucks>

I can then define a point in the center of the city, and filter by locations within a 5 mile radius:

In [6]: from django.contrib.gis.geos import fromstr

In [7]: from django.contrib.gis.measure import D

In [8]: point = fromstr('POINT(-97.6786111 30.5080556)')

In [9]: Vendor.objects.filter(location__distance_lte=(point, D(mi=5)))
Out[9]: [<Vendor: Starbucks>, <Vendor: Starbucks>, <Vendor: Starbucks>,
<Vendor: Starbucks>]

Hope you found this article helpful; if you did, please share with friends and coworkers.