5

Easy Webmapping with django-leaflet & django-geojson

 2 years ago
source link: https://fle.github.io/easy-webmapping-with-django-leaflet-and-django-geojson.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Easy Webmapping with django-leaflet & django-geojson

Let's start with an important thing: I'm a real newbie in webmapping. I've never used Postgis, Mapnik, OpenLayers or <place any webmapping tool here>. Projection, SRID, ... are just some wild words for me.

For an estate management application, I wanted to place some markers on a map : a list of properties found after a search, the location of a consulted property, ... classic. As a Django developer, this application is written with my favorite framework!

Mathieu told me about django-geojson and django-leaflet, two django apps he baked at Makina Corpus. Clearly, he didn't lie to me, django-geojson and django-leaflet make webmapping really lightweight and friendly.

The magic thing is that you don't need a spatial database or some complex geographic libraries! Mathieu and I have removed the last dependencies to GEOS a few days ago. I'm glad I could make this tiny contribution!

Django-geojson

django-geojson allows to manipulate GeoJSON (a JSON format for encoding geographic data structures) in a Django project. You can (de)serialialize objects and querysets, serve map layers through django views and store geographic data in JSON fields.

Django-leaflet

django-leaflet provides a way to play with Leaflet very easily in a Django project. It embeds Leaflet assets, provides a form widget to edit geometries and a templatetag to display maps. In addition, it's highly configurable through django settings.

An Example

Everybody loves mushrooms? Follow me, I'll show you some spots!

So I want to reference some mushroom spots, search for them and show them on a map. Here is the simple model which uses a PointField provided by django-geojson:

# models.py
from djgeojson.fields import PointField
from django.db import models

class MushroomSpot(models.Model):

    geom = PointField()

For the simplicity, when I create a mushroom spot instance, I want to point its location directly on a map. The admin widget coming with django-leaflet will help me:

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

admin.site.register(MushroomSpot, LeafletGeoAdmin)

The admin creation form looks like this and the widget allows me to place my marker easily:

django-leaflet admin widget

For information - and I think it's crazy you don't even have to know this to make it all work! -, here is the JSON structure stored in database:

{
  "type":"Point",
  "coordinates":[
    -1.4058208465576172,
    47.15301133231325
  ]
}

Edition is easy, now you'll see that display is too. To display a map, I use templatetags and filters provided by the two modules:

  • leaflet_js and leaflet_css loads my Leaflet assets
  • geojsonfeature helps me to serialize my MushroomSpot instances in a GeoJSON structure
  • leaflet_map shows up the map!

My first view aims to show search results, stored in a queryset named qs_results:

# mushroomspot_list.html
{% extends "base.html" %}
{% load leaflet_tags %}
{% load geojson_tags %}

{% block extra_assets %}
  {% leaflet_js %}
  {% leaflet_css %}
{% endblock %}

{% block content %}

    <script type="text/javascript">
      var collection = {{ qs_results|geojsonfeature|safe }};
      function map_init(map, options) {
          L.geoJson(collection).addTo(map);
      }
    </script>

    {% leaflet_map "spots" callback="window.map_init" %}

{% endblock %}

The simple code above gives me something like this:

simple map with django-leaflet and django-geosjson

Django-geojson can serialize a queryset, but it can also serialize a simple model instance. So for the detail view of a mushroom spot, code is almost the same, excepted the variable name of my data:

var collection = {{ mushroom_spot|geojsonfeature|safe }};

Note that this will dump the whole JSON into the DOM. You can also define a layer view, and obtain the data via Ajax.

A little more

A great option of django-geojson allows to automatically serialize instance properties in the standard GeoJSON feature dictionnary properties. Let's use it to add a pop-up on the marker!

I slightly adapt my model to add a description and a photo, which will be parts of my popup content. I also a write a property popupContent whose content will be serialized in the GeoJSON structure:

# models.py
from djgeojson.fields import PointField
from django.db import models

class MushroomSpot(models.Model):

    geom = PointField()
    description = models.TextField()
    picture = models.ImageField()

    @property
    def popupContent(self):
      return '<img src="{}" /><p><{}</p>'.format(
          self.picture.url,
          self.description)

I've just to change the call of geojsonfeature alittle to specify properties I want to serialize and - for this particular use case - to use the Leaflet option onEachFeature:

<script type="text/javascript">
  var collection = {{ mushroom_spot|geojsonfeature:"popupContent"|safe }};

  function onEachFeature(feature, layer) {
    if (feature.properties && feature.properties.popupContent) {
      layer.bindPopup(feature.properties.popupContent);
    }
  }

  function map_init(map, options) {
    L.geoJson(collection, {onEachFeature: onEachFeature}).addTo(map);
  }
</script>
markers with popup thanks to django-geojson and django-leaflet

And that's it!

What's next?

  • My nexts tests will be to play with more complex geometries like lines or polygons. Django-geojson provides more fields than PointField like MultiPointField, PolygonField, ...
  • For my estate management application, filling may be more simple if the marker was automatically positioned after that the user has wrote the address. I think I could use GeoPy for this.
  • An other solution would be to integrate Leaflet GeoSearch plugin to the django-leaflet admin widget.

See you!

If you have some observations or questions about this post, please leave a comment below.

Let's keep in touch on twitter or through this blog feed!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK