I want to extract polygon geometry data from a PostGIS database using python within a view and add it to my leaflet map within a template. The easiest way seemed to be to extract the data and convert it to GeoJSON using the postgis function ST_AsGeoJSON in my Django view and then render it to the template as context within the L.geoJSON(GEOJSON).addTo(map) function.
This does not work. On requesting the map page, the map is now blank and as it seems the GeoJSON is not recognised. I have been able to pass a hard-coded polygon from a view and add it to a map but the geometry data in my postgis database simply isn't valid.
Here is a view with a hardcoded polygon that is successfully printed on the map:
from django.shortcuts import render
def map_view(request, *args, **kwargs):
geo_json={
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-0.10746002197265625,
51.505537109466715
],
[
-0.11466979980468751,
51.498377681772325
],
[
-0.0968170166015625,
51.493568479510415
],
[
-0.09080886840820312,
51.502438390761164
],
[
-0.10746002197265625,
51.505537109466715
]
]
]
}
}
]
}
return render(request ,'map.html', {'geo_json': geo_json})
The map template looks as follows:
<!DOCTYPE html>
<html>
<head>
<title>Map Page</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
<style>
#map { position: relative;
width: 600px;
height: 775px;
border: 3px solid #000000;}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = L.map('map').setView([54.8,-4.45],6);
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=9GKOA9jJ3jCIWFUd8k00', {attribution: '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',}).addTo(map);
L.geoJSON({{ geo_json | safe }}).addTo(map);
</script>
</body>
</html>
Here is the leaflet map with the polygon added
Now when I try to get pass GeoJSON from my postgis database using my new view it doesn't work:
import psycopg2
from django.shortcuts import render
def map_view(request, *args, **kwargs):
connection = psycopg2.connect(database="electio5_geekdata",user="electio5_blake", password="dummypassword", host='localhost')
cursor = connection.cursor()
cursor.execute("select st_AsGeoJSON(shape) from boris_constituency limit 1")
varpoly=cursor.fetchall()
geo_json={
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": varpoly
}
]
}
return render(request ,'map.html', {'geo_json': geo_json})
I notice that the format of the GeoJSON is slightly different when I output it:-
IS FINE
{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {}, 'geometry': {'type': 'Polygon', 'coordinates' and so on and so on
IS A PROBLEM
{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {}, 'geometry': [('{"type":"MultiPolygon","coordinates" and so on and so on
The problematic GeoJSON has extra brackets and a quote preceding the second "type" key
So my question is:-
1/ Is it possible to reformat the problematic GeoJSON? I had difficulty stripping out the unwanted characters which wrap the list
2/ Or can I extract just the co-ordinates and pass those to the relevant part of geo_json?
3/ Or any way at all I can extract the polygon data from postgis and add it to the leaftlet map
btw you may wonder why I'm using a cursor rather than using the Django model object which has a GeoJSON method. This approach gave me a GDAL error due to the libraries not being properly configured and is a problem for another day!
Big thanks for your attention to this.
Phil #anoobintrouble
fetchAll
is giving you a list and you are using it as if it was just one element. So you need to usevarpoly[0]
or iteratevarpoly
and each polygon turn to a feature in the features array of the GeoJSON. – cabesuon{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {}, 'geometry': '{"type":"MultiPolygon","coordinates":
still with a single quote preceding the second type statement which I think is causing a problem. Where has it come from and can it be got rid of? – blakejson.loads
to get the object, remember that it is giving you a string in geojson format. – cabesuon"geometry": json.loads(varpoly[0])
, that convert the string value in json format to a "geojson object" (python json basic usage) – cabesuon