0

I wan't to display GeoJSON data on a Leaflet map using Django. Data is from a PostgreSQL database, I have created a view with raw JSON which returns me data but I wan't to add this to a Leaflet map as a GeoJSON. My Leaflet map display but empty (without data) and I can't even add a simple marker or a baselayer.

I have read all I found about this (similar issue 1, similar issue 2, similar issue 3, similar issue 4) and tried several codes without success.

Am I missing something big ?

parcelle/views.py

from .models import Parcelle
from django.http import HttpResponse
from django.core.serializers import serialize
from django.views.generic import TemplateView

# GeoJSON
def geojson_view(request):
    geom_as_geojson = serialize('geojson', Parcelle.objects.all())
    return HttpResponse(geom_as_geojson, content_type='json')

def parcelle_view(request):
    redis_key = 'parcelles'
    parcelle_as_geojson = cache.get(redis_key)
    if not parcelle_as_geojson:
        parcelle_as_geojson = serialize('geojson', Parcelle.objects.all())
        cache.set(redis_key, parcelle_as_geojson)
    return HttpResponse(parcelle_as_geojson, content_type='json')

# Leaflet page
class MainPageView(TemplateView):
    template_name = 'parcelle/index.html'

parcelle/models.py

from __future__ import unicode_literals
from django.contrib.gis.db import models

class Parcelle(models.Model):
    reference_cadastrale = models.CharField(max_length=14)
    location = models.MultiPolygonField(srid=4326)

    def __str__(self):
        return '{}'.format(self.reference_cadastrale)

    def __unicode__(self):
        return '{}'.format(self.reference_cadastrale)

parcelle_mapping = {
    'reference_cadastrale': 'reference_cadastrale',
    'location' : 'MULTIPOLYGON'
}

parcelle/admin.py

from django.contrib.gis import admin
from .models import Parcelle
from leaflet.admin import LeafletGeoAdmin

admin.site.register(Parcelle, LeafletGeoAdmin)

foncier/urls.py

from django.contrib import admin
from django.urls import path
from parcelle.views import geojson_view, parcelle_view, MainPageView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('parcelle/', MainPageView.as_view(), name='parcelles'),
    path('data/', geojson_view, name='data'),
]

foncier/settings.py

import os    

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'bla bla bla bla'    

DEBUG = True

ALLOWED_HOSTS = []    

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.gis',
    'foncier',
    'parcelle',
    'leaflet',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

MIDDLEWARE_CLASSES = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
]

CACHES = {
    'default': {
        'BACKEND': 'redis_cache.RedisCache',
        'LOCATION': '127.0.0.1:8000',
    },
}

ROOT_URLCONF = 'foncier.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "templates")],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'foncier.wsgi.application'    
    
DATABASES = {
    'default': {
        'ENGINE': 'django.contrib.gis.db.backends.postgis',
        'NAME': 'myDB',
        'USER': 'myUser',
        'PASSWORD': 'myPSWD',
        'HOST': 'myHost',
        'PORT': '1111' # Fake value
    }
}     


AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True
  
STATIC_URL = '/static/'

SERIALIZATION_MODULES = {
    "geojson": "django.contrib.gis.serializers.geojson",
}

STATICFILES_DIR = (
    os.path.join(BASE_DIR, 'static'),
)

LEAFLET_CONFIG = {
    'DEFAULT_CENTER': (43.446577,6.079717),
    'DEFAULT_ZOOM': 9,
}

parcelle/templates/parcelle/index.html

<html>
{% load leaflet_tags %}
{% load static %}
    <head>
        <title>My map</title>
        {% leaflet_js %}
        {% leaflet_css %}
        <script src="{% static 'leaflet-ajax/dist/leaflet.ajax.min.js' %}"></script>
        <script src="{% static 'spin.js/spin.min.js' %}"></script>
        <script src="{% static 'leaflet-spin/leaflet.spin.js' %}"></script>
        <style>
        #main {width:100%; height:100%;}
        </style>
    </head>
    <body>
        <script type="text/javascript">
            function map_init_basic (map, options) {
            
                // Layer
                var geojsonParcelleLayer = new L.GeoJSON.AJAX("{% url 'parcelles' %}", {
                    onEachFeature:function(feature, layer) {
                        layer.bindPopup(feature.properties.reference_cadastrale.toString());
                    }
                });
                geojsonParcelleLayer.addTo(map);
                
                // Baselayer
                var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
                var esri = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}');
                var google = L.tileLayer('http://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}');  
                var baseLayers = {
                    "OSM": osm,
                    "ESRI": esri,
                    "Google Hybrid": google
               };
               L.control.layers(baseLayers).addTo(map);
            }
        </script>
        {% leaflet_map "main" callback="window.map_init_basic" %}
    </body>
</html>

Edit

var dataurl = '{% url "parcelles" %}';
$.getJSON(dataurl, function (data) {
    L.geoJson(data, {
        onEachFeature:function(feature, layer) {
            layer.bindPopup(feature.properties.reference_cadastrale.toString());
        }
    }).addTo(map);
});
  • 2
    AJAX calls are usually async and you have to wait for the completition of the call to add the layer to the map. If you look in the docs at github.com/calvinmetcalf/leaflet-ajax, you'll see you have to wait for data:loaded event and only then add layer to the map. – TomazicM Jul 22 at 19:04
  • Thanks for this reply. I found your answer on this post. How would you write this ? I've edited my post with an example. – GeoGyro Jul 22 at 19:34
  • 1
    Since you have only one layer, there's no need for checkAllLoaded() function, just geojsonParcelleLayer.on("data:loaded",function(){geojsonParcelleLayer.addTo(map);}); – TomazicM Jul 22 at 19:45
  • Just a feedback : data display on the map with $.getJSON. I also add import json and from django.http import JsonResponse in views.py. I've updated my post with the right code for Leaflet. – GeoGyro Jul 23 at 11:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.