Oct 24, 2008

How to create a view to add an object...

How to create a view to add an object with a PointField

All the files described below are part of a django app called dj_cartographe. The objective of this short wiki page is to help you to create a web page where you will be able to add object RunningWaterOutage.

Let us take the following models that represents a simplified version of what could be a RunningWaterOutage :


# dj_cartographe/models.py
from django.contrib.gis.db import models

class RunningWaterOutage(models.Model):
"""A spatial model for interesting locations """
name = models.CharField(max_length=50, )
description = models.TextField()
creation_date = models.DateTimeField(auto_now_add=True)
start_date = models.DateTimeField()
end_date = models.DateTimeField()

geometry = models.PointField(srid=4326) #EPSG:4236 is the spatial reference for our data
objects = models.GeoManager() # so we can use spatial queryset methods

def __unicode__(self): return self.name


In order to use this model in django admin you should configure it as follow :


# dj_cartographe/admins.py
from django.contrib.gis import admin
from django.contrib.gis.maps.google import GoogleMap
from dj_cartographe.models import *
class RunningWaterOutageAdminOptions(admin.OSMGeoAdmin):
list_display = ('name', 'description', 'start_date', 'end_date')
list_filter = ('name', 'description', 'start_date', 'end_date')
fieldsets = (
('Location Attributes', {'fields': (('name', 'description', 'start_date', 'end_date',))}),
('Editable Map View', {'fields': ('geometry',)}),
)
# Default GeoDjango OpenLayers map options
scrollable = False
map_width = 700
map_height = 325
GMAP = GoogleMap(key='<YOUR GOOGLE KEY THERE>') # Can also set GOOGLE_MAPS_API_KEY in settings
class RunningWaterOutageGoogleAdminOptions(admin.OSMGeoAdmin):
extra_js = [GMAP.api_url + GMAP.key]
map_template = 'gis/admin/google.html'
list_display = ('name', 'description', 'start_date', 'end_date')
list_filter = ('name', 'description', 'start_date', 'end_date')
fieldsets = (
('Location Attributes', {'fields': (('name', 'description', 'start_date', 'end_date',))}),
('Editable Map View', {'fields': ('geometry',)}),
)
# Default GeoDjango OpenLayers map options
scrollable = False
map_width = 700
map_height = 325
# Register our model and admin options with the admin site
admin.site.register(RunningWaterOutage, RunningWaterOutageAdminOptions)
# Register the google enabled admin site
google_admin = admin.AdminSite()
google_admin.register(RunningWaterOutage, RunningWaterOutageGoogleAdminOptions)


It is interesting to note that in the example above we have created in fact 2 instances of admin site.

Now the interesting part of this recipe, you will find below a method that will enable you to provide a map as user interface to enter the location of the RunningWaterOutage.


#dj_cartographe/forms.py
from django.forms import ModelForm
from django.forms.fields import CharField
from django.contrib.gis.admin.options import GeoModelAdmin
from dj_cartographe.admin import google_admin

from dj_cartographe.models import RunningWaterOutage

geomodeladmin = GeoModelAdmin(RunningWaterOutage, google_admin)
db_field = RunningWaterOutage._meta.get_field('geometry')

class RunningWaterOutageForm(ModelForm):
# Overiding the default Field type
geometry = CharField(widget=geomodeladmin.get_map_widget(db_field))
class Meta:
model = RunningWaterOutage

class Media:
js = (
"http://openlayers.org/api/2.6/OpenLayers.js",
)


This RunningWaterOutageForm will contain when rendered on a template a nice OpenLayers map that your users will be able to use instead of having to key in the Point in a textarea.

Now the template :

# dj_cartographe/templates/running_water_outage_edit.html
{% extends "base.html" %}

{% block title %}my first map{% endblock %}
{% block media %}
{{ form.media }}
{% endblock %}

{% block content %}
<h1>my first map</h1>
<form action="." method="POST">
{{form}}
<input type="submit" value="Submit" />
</form>
{% endblock %}


There is nothing special there, however it is interesting to note that we use {{ form.media }} to pull in the javascript.



The last piece is to create the view :



#dj_cartographe/views.py
from django.shortcuts import render_to_response
from dj_cartographe.models import RunningWaterOutage
from dj_cartographe.forms import RunningWaterOutageForm


def running_water_outage_add(request):

if request.method == "POST":
running_water_outage_form = RunningWaterOutageForm(request.POST)
if running_water_outage_form.is_valid():
running_water_outage_form.save()
else:
running_water_outage_form = RunningWaterOutageForm()

return render_to_response("running_water_outage_edit.html",
{"form" : running_water_outage_form,
})





Here it is the result of this small recipe :