Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jlandercy opened this issue Apr 2, 2023 · 1 comment

Comments

@jlandercy
Copy link

jlandercy commented Apr 2, 2023

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

@jlandercy jlandercy changed the title Idea for support for RawQuery using the classical flow of Django and DRF Idea of support for RawQuery using the classical class based flow of Django and DRF Apr 2, 2023
@auvipy
Copy link
Collaborator

auvipy commented Apr 27, 2023

what about using the query as django model manager?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants