When dealing with GeoDjango the need for RawQuery is important as PostGIS queries are inherently difficult to write with the classical Django Queryset pattern.
When trying to bind everything together I have found a simple way to do it, and I share the recipe here because I might not be the only one having this need and there is no obvious documentation about it. At least this issue can last as a documentation.
But I also think it is a good use case to extend this package (which is very convenient by the way). I have the feeling it might be easy to draw a pull request from here. See my stack overflow request for peer reviewing for more details.
With the current version, the best way I have found to perform it, is:
class Location(Model):
geom = models.PointField()
class CircleSerializer(GeoFeatureModelSerializer):
id = serializers.IntegerField(required=True)
circle = GeometrySerializerMethodField()
def get_circle(self, obj):
return GEOSGeometry(obj.circle)
class Meta:
model = Location
geo_field = "circle"
fields = ('id',)
class CircleViewSet(ListAPIView):
queryset = Location.objects.raw("""
SELECT id, ST_Buffer(L.geom::Geography, 800)::Geometry AS circle
FROM location AS L;
""")
serializer_class = CircleSerializer
And it works as expected, and it is clean and concise.
But maybe something cleaver can be done to withdraw the need of explicitly cast the GIS column which in this scenario is returned as a str holding the geometry binary representation. Passing it to the GEOS geometry constructor solve the problem.
Maybe creating the field object, it can detect if the QuerySet is actually a RawQuery and add the extra GEOS casting on the fly. That would makes the code even simpler. Something like:
class Location(Model):
geom = models.PointField()
class CircleSerializer(GeoFeatureModelSerializer):
id = serializers.IntegerField(required=True)
circle = GeometrySerializerField() # <-- Some magic that perhaps could land here
#circle = RawGeometrySerializerField() # <-- Or into a new object
class Meta:
model = Location
geo_field = "circle"
fields = ('id',)
class CircleViewSet(ListAPIView):
queryset = Location.objects.raw("""
SELECT id, ST_Buffer(L.geom::Geography, 800)::Geometry AS circle
FROM location AS L;
""")
serializer_class = CircleSerializer
Indeed it must not break the flow for other process. Another kind of isolation could be a totally new field object.
I open the discussion, let me know if it makes sense.
When dealing with GeoDjango the need for RawQuery is important as PostGIS queries are inherently difficult to write with the classical Django Queryset pattern.
When trying to bind everything together I have found a simple way to do it, and I share the recipe here because I might not be the only one having this need and there is no obvious documentation about it. At least this issue can last as a documentation.
But I also think it is a good use case to extend this package (which is very convenient by the way). I have the feeling it might be easy to draw a pull request from here. See my stack overflow request for peer reviewing for more details.
With the current version, the best way I have found to perform it, is:
And it works as expected, and it is clean and concise.
But maybe something cleaver can be done to withdraw the need of explicitly cast the GIS column which in this scenario is returned as a
str
holding the geometry binary representation. Passing it to the GEOS geometry constructor solve the problem.Maybe creating the field object, it can detect if the QuerySet is actually a RawQuery and add the extra GEOS casting on the fly. That would makes the code even simpler. Something like:
Indeed it must not break the flow for other process. Another kind of isolation could be a totally new field object.
I open the discussion, let me know if it makes sense.
Best regards,
Jean