3

I'm building a REST API to manage geo-related data.
My front-end developer wants to retrieve the centroid of polygons, depending on zoom level, in geoJSON format.

My polygon model is as follows:

...
from django.contrib.gis.db import models as geomodels
class Polygon(geomodels.Model):
    fk_owner = models.ForeignKey(User, on_delete=models.DO_NOTHING, blank=True)
    external_id = models.CharField(max_length=25, unique=True) 
    func_type = models.CharField(max_length=15)
    coordinates = geomodels.PolygonField(srid=3857)
    properties = JSONField(default={}) 

The API currently returns things like this:

"type": "FeatureCollection",
"features": [
 {
     "type": "Feature",
     "geometry": {
         "type": "Polygon",
         "coordinates": [[[..]]]
      }
  }]

And I use rest_framework_gis.serializers.GeoFeatureModelSerializer to serialize my data.

I see the following ways to get the centroid:

  1. Add a column centroid to my model: I don't want to do this
  2. Create a database view of my model: Django does not manage database views and I don't want to write a custom migration
  3. Use the same model and add an extra(...) to my orm statement: I tried but things get hard in or before serialization, because in the model the type is Polygon, and the centroid is a Point. The error is the following:

    TypeError: 
        Cannot set Polygon SpatialProxy (POLYGON) with value of type:
        <class 'django.contrib.gis.geos.point.Point'>
    

The expected output should be:

"type": "FeatureCollection",
"features": [
 {
     "type": "Feature",
     "geometry": {
         "type": "Point",
         "coordinates": [..]
      }
  }]

What is your opinion ?

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
GwydionFR
  • 787
  • 1
  • 10
  • 25

1 Answers1

5

You can use a combination of the following methods:

  1. AsGeoJSON, which

    Accepts a single geographic field or expression and returns a GeoJSON representation of the geometry.

  2. Centroid() which

    Accepts a single geographic field or expression and returns the centroid value of the geometry.

  3. .annotate() which

    Annotates each object in the QuerySet with the provided list of query expressions.
    [...]
    Each argument to annotate() is an annotation that will be added to each object in the QuerySet that is returned.


Example:

The following query:

Polygon.objects.annotate(geometry=AsGeoJSON(Centroid('coordinates')))

will add a field named 'geometry' to the Polygon queryset which will contain the centroid calculated from the coordinates field of every Polygon object of your given model.

Community
  • 1
  • 1
John Moutafis
  • 22,254
  • 11
  • 68
  • 112