Jun 04 2008

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

Published by tylere at 10:00 pm under Geospatial Technologies

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 test_geodjango.slicename.com website.

mkdir -p ~/website/test_geodjango.slicename.com/{public,private,log,cgi-bin,backup}

Create a GeoDjango Project

Create a default Django project…

cd ~/website/test_geodjango.slicename.com/public
django-admin.py startproject test_geodjango

Add the GDAL library path to the Django project settings…

nano ~/website/test_geodjango.slicename.com/public/test_geodjango/settings.py

Add the following line so your Django project can found the GDAL library…

GDAL_LIBRARY_PATH = '/usr/local/lib/libgdal.so'

Test out the project (using the internal web server)…

python ~/website/test_geodjango.slicename.com/public/test_geodjango/manage.py 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 http://127.0.0.1:8001/ 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/test_geodjango.slicename.com/public/test_geodjango/views.py

and insert the following code

from django.http import HttpResponse
import datetime

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

Edit the URL configuration file

nano ~/website/test_geodjango.slicename.com/public/test_geodjango/urls.py

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/test_geodjango.slicename.com

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: test_geodjango.domain.com
# public: /home/demo/website/test_geodjango.domain.com/

<VirtualHost *>
    # Admin email, Server Name (domain name) and any aliases
    ServerAdmin webmaster@slicename.com
    ServerName test_geodjango.slicename.com

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

    <Directory "/">
        Order deny,allow
        Allow from all
    </Directory>

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

    # Custom log file locations
    LogLevel warn
    ErrorLog /home/demo/website/test_geodjango.slicename.com/log/error.log
    CustomLog /home/demo/website/test_geodjango.slicename.com/log/access.log combined
</VirtualHost>

Enable the site and reload apache to use the new configuration…

sudo a2ensite test_geodjango.slicename.com
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

11.222.333.444 test_geodjango.slicename.com

Test it out, by opening up a Web browser and go to http://test_geodjango.slicename.com/time/ 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

(reference: http://www.djangobook.com/en/1.0/chapter05/)
Edit the settings file for the Django project…

nano  ~/website/test_geodjango.slicename.com/public/test_geodjango/settings.py

And update the database connection parameters

DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'test_geodjango_db'
DATABASE_USER = 'testuser'
DATABASE_PASSWORD = 'password'
DATABASE_HOST = ''
DATABASE_PORT = ''

Test the database connection

Open up a Python shell for the project…

cd ~/website/test_geodjango.slicename.com/public/test_geodjango
python manage.py 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.
(InteractiveConsole)
>>>

>>> 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 http://www.djangobook.com/en/1.0/chapter05/ and http://code.djangoproject.com/wiki/GeoDjango)
Create a Django application and edit the model configuration file…

python manage.py startapp testapp
nano testapp/models.py

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…

nano settings.py

and edit the INSTALLED_APPS section as follows

INSTALLED_APPS = (
    #'django.contrib.auth',
    #'django.contrib.contenttypes',
    #'django.contrib.sessions',
    #'django.contrib.sites',
    'test_geodjango.testapp',
)

Sync the database with the Django model…

python manage.py 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 manage.py 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))' )
>>> d1.save()
>>> 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.

[<District: District object>]

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/test_geodjango.slicename.com/public/test_geodjango/testapp/views.py

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 = datetime.datetime.now()
    pointWkt = 'POINT(-95.362293 29.056539)'
    districtSet = District.objects.filter(poly__contains=pointWkt)
    html = "It is now %s." % now
    html += "<br/><br/>"
    if len(districtSet)>0:
        for district in districtSet:
            html += "%s is in %s" % (pointWkt, district.name)
    else:
        html += "%s is not within any districts" % pointWkt
    return HttpResponse(html)

Update the URL configuration…

nano ~/website/test_geodjango.slicename.com/public/test_geodjango/urls.py

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: http://test_geodjango.slicename.com/test/
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…

Trackback URI | Comments RSS

Leave a Reply

You must be logged in to post a comment.