Showing posts with label GIS. Show all posts
Showing posts with label GIS. Show all posts

Jan 31, 2009

Enable distutils for a django reusable app

As you might already be aware Pinax move to distutils, this change has been described by James Tauber in this post. Today I have decided to make my feet wet with this approach for a django reusable app. I have been guided by jezdez on #pinax.
Before starting I would recommend you to read this page, yes I know, it is a bit long but very interesting. after this reading you will be well prepared to start to work on you django reusable app.

I have used one of my project django-geotagging to experiment with this approach. The project can be found on launchpad there. The good news about this approach is that all the major rcs are supported : SVN, BZR, HG, ... If your favorite versionning system is missing there is a good chance that I just forget to mention it. This list is not exhaustive.

The core of this approach is a file called setup.py that need to be paced at the root of your repository, most of its argument are self explanatory.

This file enable you to setup a complete env in 4 steps :
The coolness of this increase with the number of reusable apps you have to install in order to build your web project.

I would be glad to learn from you what kind of cool things can be done once this infrastructure is in place.

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,
related_name="content_type_set_for_%(class)s")
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.

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 :