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 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/


# 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


Order deny,allow
Allow from all



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


# 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


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.
[]

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 += "

"
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...

No comments:

Post a Comment