Wednesday, June 4, 2008

GeoDjango on Slicehost: Creating a GeoDjango Project (4 of 4)

This final post goes over how to create a test GeoDjango project.

Creating a Website Directory Structure

Create a location for the website directory structures.
mkdir ~/website

Create a directory structure for the website.
mkdir -p ~/website/{public,private,log,cgi-bin,backup}

Create a GeoDjango Project

Create a default Django project...
cd ~/website/ startproject test_geodjango

Add the GDAL library path to the Django project settings...
nano ~/website/

Add the following line so your Django project can found the GDAL library...
GDAL_LIBRARY_PATH = '/usr/local/lib/'

Test out the project (using the internal web server)...
python ~/website/ runserver 8001

You should see a response like the following...
Validating models... 0 errors found Django version 0.97-pre-SVN-7547, using settings 'test_geodjango.settings' Development server is running at Quit the server with CONTROL-C.

Even though the server is running, you would be able to see a Django page since port 8001 is not open. Quit the server for now...

Create a new view

Create a new view file for the project...
nano ~/website/

and insert the following code
from django.http import HttpResponse
import datetime

def current_datetime(request):
now =
html = "It is now %s." % now
return HttpResponse(html)

Edit the URL configuration file
nano ~/website/

Replace the content with the following code which will be used to display a Django test page...
from django.conf.urls.defaults import *
from test_geodjango.views import current_datetime

urlpatterns = patterns('',
(r'^time/$', current_datetime),

Configure Apache to recognize the new virtual host
sudo nano /etc/apache2/sites-available/

Add the following to configure the virtual host
# Place any notes or comments you have here
# It will make any customization easier to understand in the weeks to come

# domain:
# public: /home/demo/website/

# Admin email, Server Name (domain name) and any aliases

# Index file and Document Root (where the public files are located)
#DirectoryIndex index.html
DocumentRoot /home/demo/website/

Order deny,allow
Allow from all

SetHandler python-program
PythonPath "['/home/demo/website/'] + sys.path"
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE test_geodjango.settings
PythonDebug On

# Custom log file locations
LogLevel warn
ErrorLog /home/demo/website/
CustomLog /home/demo/website/ combined

Enable the site and reload apache to use the new configuration...
sudo a2ensite
sudo /etc/init.d/apache2 reload
sudo apache2ctl graceful

On your local computer, edit the /etc/hosts file and add the following line to setup an override

Test it out, by opening up a Web browser and go to You should see a page that shows something like...
It is now 2008-05-24 11:22:33.991752.

Create a PostGIS database

Next we will create a PostGIS database for the project... (I have included the shell prompts to make it more clear what user/context is running the command.)
myslice ~: sudo su - postgres
postgres@myslice:~$ createuser -SDRP testuser
postgres@myslice:~$ createdb -O testuser test_geodjango_db
postgres@myslice:~$ createlang plpgsql test_geodjango_db
postgres@myslice:~$ psql -d test_geodjango_db -f /usr/share/lwpostgis.sql
postgres@myslice:~$ psql -d test_geodjango_db -f /usr/share/spatial_ref_sys.sql
postgres@myslice:~$ psql test_geodjango_db
test_geodjango_db=# ALTER TABLE geometry_columns OWNER TO testuser;
test_geodjango_db=# ALTER TABLE spatial_ref_sys OWNER TO testuser;
test_geodjango_db=# \q
postgres@myslice:~$ exit
myslice ~:

Configure the Django database configuration

Edit the settings file for the Django project...
nano  ~/website/

And update the database connection parameters
DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'test_geodjango_db'
DATABASE_USER = 'testuser'

Test the database connection

Open up a Python shell for the project...
cd ~/website/
python shell

Python 2.5.2 (r252:60911, Apr 21 2008, 11:17:30)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> from django.db import connection
>>> cursor = connection.cursor()

If the cursor = connection.cursor() command did not produce any response, then the database connection was successfully made.

Add a Django App and Define a Model

(see and
Create a Django application and edit the model configuration file...
python startapp testapp
nano testapp/

And replace with the following...
from django.contrib.gis.db import models

class District(models.Model):
name = models.CharField(max_length=35)
num  = models.IntegerField()
poly = models.PolygonField()
objects = models.GeoManager()

class School(models.Model):
name  = models.CharField(max_length=35)
point = models.PointField()
objects = models.GeoManager()

Install the Django App

Edit the settings configuration file...

and edit the INSTALLED_APPS section as follows

Sync the database with the Django model...
python syncdb

which should produce the following...
Creating table testapp_school
Creating table testapp_district
Installing custom SQL for testapp.School model
Installing custom SQL for testapp.District model

Test access to the database from the command line...
python shell
>>> from testapp.models import District, School
>>> d1 = District(name='Test District 1' , num=1, poly='POLYGON((-96 29,-95 29,-95 30,-96 29))' )
>>> qs1 = District.objects.filter(poly__bbcontains='POINT(-95.362293 29.756539)')
>>> qs1

Python should echo back a District object. This returns an array with a single district record, since the district polygon's bounding box contains the point.

Try again a query that does not return any points (since the point is not contained within the district polygon)...
>>> qs2 = District.objects.filter(poly__contains='POINT(-95.362293 29.756539)')
>>> qs2


Displaying GeoDjango Results on a Web Page

Create another view file for the project...
nano ~/website/

and add a view that returns the results of a GeoDjango query...
from django.http import HttpResponse
import datetime
from models import District, School

def test_geodjango_view(request):
now =
pointWkt = 'POINT(-95.362293 29.056539)'
districtSet = District.objects.filter(poly__contains=pointWkt)
html = "It is now %s." % now
html += "

if len(districtSet)>0:
for district in districtSet:
html += "%s is in %s" % (pointWkt,
html += "%s is not within any districts" % pointWkt
return HttpResponse(html)

Update the URL configuration...
nano ~/website/

to match the following...
from django.conf.urls.defaults import *
from test_geodjango.views import current_datetime
from test_geodjango.testapp.views import test_geodjango_view

urlpatterns = patterns('',
(r'^time/$', current_datetime),
(r'^test/$', test_geodjango_view),

Reload the Apache configuration...
sudo /etc/init.d/apache2 reload
sudo apache2ctl graceful

If you get a message saying that httpd is not running, try reloading the Apache configuration again...
sudo /etc/init.d/apache2 reload
sudo apache2ctl graceful

Test out the web page...

Point a browser at:
You should see something similar to
It is now 2008-06-04 21:26:17.022444.

POINT(-95.362293 29.056539) is in Test District 1

if that works, you now have a working (although trivial) GeoDjango website served via Apache. Now its up to you to make do something interesting. Good luck...

No comments:

Post a Comment