Jan 19, 2009

How to use the same widget as GeoDjango

At the end of this post you will be able to use the same widget than the automatically generated admin interface in geodjango. I spent quite sometimes today to rediscover how to do this. Yes, rediscover because I have already written about this a couple of month ago. My first post on that topic can be read there. Happily "jbronn" on #geodjango gave the solution to me.

# Getting an instance so we can generate the map widget; also
# getting the geometry field for the model.
admin_instance = PointAdmin(Point, admin.site)
point_field = Point._meta.get_field('point')

# Generating the widget.
PointWidget = admin_instance.get_map_widget(point_field)

In fact all the complication at the moment there is no static widget that widget you could use in your own form. You have to build them dynamically.

I am now going to break down the 3 lines of code.
PointAdmin is the ModelAdmin class which is a representation of a model in the admin interface. Here it is an example :

from django.contrib.gis import admin
from geotagging.models import Point

class PointAdmin(admin.GeoModelAdmin):
list_filter = ('content_type','point' )
list_display = ('object', 'point', 'content_type', 'object_id')

Point in the model we are working on so Point._meta.get_field('point') is accessing the field called point of the Point mode. The code below should help you to understand :

class Point(models.Model):
point = models.PointField(verbose_name=_("point"),srid=4326)
content_type = models.ForeignKey(ContentType,
object_id = models.CharField(_('object ID'),max_length=50)
object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_id")
objects = models.GeoManager()

def __unicode__(self):
return 'Point for %s' % self.object

The last line is actually where the geodjango specificity is :
* PointWidget = admin_instance.get_map_widget(point_field)
get_map_widget is defined here

Now that we have a PointWidget we can use it in our form. Here is is a small example :

class PointForm(forms.ModelForm):
point = forms.CharField(widget=PointWidget())
class Meta:
model = Point
exclude = ("content_type","object_id")
class Media:
js = ("http://openlayers.org/api/2.6/OpenLayers.js",)

Now you can use geodjango super widgets in your forms.