Django RF: POST geometry from Leaflet Draw to Post

2020-07-26 12:37发布

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.

  1. Could anyone provide some guidance on how to set up this "geojson-to-geometry" conversion?
  2. 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'      

0条回答
登录 后发表回答