Edit Django geometries fields with Leaflet

After the previous article regarding Django, Leaflet and GeoJSON, I wanted to highlight the simplicity of GeoDjango geometries creation and edition with django-leaflet.

It relies on Leaflet.draw for user interactions.

note:Until recently, it was restricted to Django 1.6+, but Gaël contributed a backport that allows Django 1.4.2+ users to have them too !

In Django Adminsite

Given a GeoDjango model as usual

# models.py
from django.db import models
from django.contrib.gis.db import models as gismodels


class MushroomSpot(gismodels.Model):

    name = models.CharField(max_length=256)
    geom = gismodels.PolygonField()

    objects = gismodels.GeoManager()

    def __unicode__(self):
        return self.name

Register using Leaflet GeoAdmin

It's as simple as :

from django.contrib import admin
from leaflet.admin import LeafletGeoAdmin

from .models import MushroomSpot


admin.site.register(MushroomSpot, LeafletGeoAdmin)

In forms views

Edition view usign Class-Based View

from django import forms
from django.views.generic import UpdateView
from leaflet.forms.widgets import LeafletWidget

from .models import MushroomSpot


class MushroomSpotForm(forms.ModelForm):
    class Meta:
        model = MushroomSpot
        fields = ('name', 'geom')
        widgets = {'geom': LeafletWidget()}


class EditMushroomSpot(UpdateView):
    model = MushroomSpot
    form_class = MushroomSpotForm
    template_name = 'form.html'

Form template with Leaflet tags

{% load leaflet_tags %}
<html>
  <head>
    {% leaflet_js plugins="forms" %}
    {% leaflet_css plugins="forms" %}
  </head>
  <body>
    <h1>Edit {{ object }}</h1>
    <form method="POST">
        {{ form }}
        {% csrf_token %}
        <input type="submit"/>
    </form>
  </body>
</html>

Going further...

The Django form widget has a couple of options, that can tweak some aspects of the map (size, read-only, ...).

But some advanced usage might require specific interactions or behaviour, beyond Django field and widgets customizations.

Custom field JavaScript component

The frontend field component behaviour and initialization is also pluggable, and can be used to add extra controls, layers or whatever.

Custom.GeometryField = L.GeometryField.extend({
    addTo: function (map) {
        L.GeometryField.prototype.addTo.call(this, map);

        var filecontrol = map.filecontrol = L.Control.fileLayerLoad();
        map.addControl(filecontrol);
    }
});
class CustomLeafletWidget(LeafletWidget):
    geometry_field_class = 'Custom.GeometryField'

Custom de/serialization of form field value

The Javascript component for de/serializing fields value is pluggable, can be used to override the way the geometries are sent to the form.

Custom.FieldStore = L.FieldStore({
    save: function (layer) {
        this.formfield.value = {"latlngs": layer.getLatLngs()};
    }
});
class CustomLeafletWidget(LeafletWidget):
    field_store_class = 'Custom.FieldStore'

Help us improve django-leaflet !

We built django-leaflet at Makina Corpus for some our Webmapping projects. It is used in production and gives us satisfaction in most use-cases.

If our initial design does not match your needs, please tell us what you think !

For example, personnally, I would like to remove the <script> tag in the map template, and pass configuration entries through the DOM instead...

...your turn !

#django, #leaflet, #gis, #geojson - Posted in the Dev category