I'm trying to store some geometry in a PostGIS DB which is created using Leaflet Draw.
The following answer only covers the first part: how to transform the drawn shape into GeoJSON, i.e.:
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType
var layer = e.layer;
// Do whatever else you need to. (save to db, add to map etc)
drawnItems.addLayer(layer);
//Export to DB (source: https://stackoverflow.com/a/24019108/3976696)
var shape = layer.toGeoJSON()
shape_for_db = JSON.stringify(shape);
For example, shape_for_db
contains:
{
"type": "Feature",
"properties": {},
"geometry": {
"type":"Polygon",
"coordinates":[[[-0.217073,51.918784],[-0.361362,51.101904],[-0.96918,53.4925],[-0.217073,51.018784]]]
}
}
However, I can't find any solution to successfully insert the geometry in the DB.
So far, based on this, I've tried the following:
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json",
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
url: "/en/api/geomtable/",
data: JSON.stringify({"description":"this is a test", "geom":shape_for_db}),
success : function(result) {
console.log(result);
}
});
This returns a 400 Bad Request with the following error:
Unable to convert to python object: Invalid geometry pointer returned from "OGR_G_CreateGeometryFromJson"."
What should I make of this error? Should I parse the GeoJSON first or something?
UPDATE:
I narrowed a bit the problem, but still haven't succeeded to store GeoJSON in a PostGIS geometry column.
First, I figured out how to do it via SQL:
INSERT INTO citydb.cityobject (gmlid, objectclass_id, envelope)
VALUES
(
'This is a test insert',
23,
ST_SetSRID(ST_GeomFromGeoJSON
(
'{
"type":"Polygon",
"coordinates":[
[7.814375,52.743552],
[12.9375,51.886624],
[7.375,52.520452]
]
}'
),2056)
)
Next, I confirmed that the Ajax above successfully posts non-geometry data to PostgreSQL (i.e. when I remove "geom":shape_for_db
from the posted geojson), and fails as soon as I include the geometry (i.e. I get 400 Bad request
).
Therefore, I suppose I have to setup my serializer or something in Django to do the equivalent of ST_SetSRID(ST_GeomFromGeoJSON(...))
.
I found that the equivalent in Django should be GEOSGeometry, but I am quite unsure on how/where to set this up.
- Could anyone provide some guidance on how to set up this "geojson-to-geometry" conversion?
- And more generally, should I really be doing this conversion in the Django Rest Framework, or are there compelling reasons to do it in the Javascript part, or even directly in the PostgreSQL database (e.g. a function triggered when a geojson is written in the geometry column)?
Currently, my Django/DRF setup is as follows:
views.py
#Viewsets and serializers based on https://www.django-rest-framework.org/tutorial/quickstart/
class CityobjectViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Cityobject information to be viewed or edited.
"""
lookup_field = 'id'
queryset = Cityobject.objects.all()
serializer_class = CityobjectSerializer
# filter_backends = [DjangoFilterBackend] #allows Django-ORM filters in URL
filter_fields = ('id','gmlid','name',)
urls.py
router = routers.DefaultRouter()
router.register(r'cityobject', views.CityobjectViewSet, 'cityobject')
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
serializers.py
class CityobjectSerializer(GeoFeatureModelSerializer):
class Meta:
model = Cityobject
#Provide only relevant fields for frontend
fields = (
"objectclass",
"gmlid",
"name",
"description",
"envelope",
"creation_date",
"xml_source"
)
geo_field = 'envelope'