Skip to content

Idea of support for RawQuery using the classical class based flow of Django and DRF #281

@jlandercy

Description

@jlandercy

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.

Best regards,

Jean

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions