Search code examples
pythondjangodjango-rest-frameworkgeodjango

How to apply a transformation on a field when serializing?


In Django, how does one apply a custom transformation while serializing a field?

For instance, I have a model which has a geometry field, which is stored in a specific coordinate system. Now, for this one serializer, I'd like to perform a conversion that converts the coordinates to another coordinate system. How is that done?

The serializer currently looks like this:

class LinkWithGeometrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Link
        fields = ['link_type',
                  'geometry',
                  ]

The geometry is the field that should have a transformation applied to it.


Solution

  • As Iklinac pointed out, you can use a custom field, but that only pays off when you can reuse it.

    There's two other common approaches:

    Keep it at serializer level:

    class LinkWithGeometrySerializer(serializers.ModelSerializer):
        geometry = serializers.SerializerMethodField()
        class Meta:
            model = Link
            fields = ['link_type', 'geometry',]
    
        @staticmethod
        def get_geometry(obj: Link):
            # for example obtain srid from context, by passing it in via view or hardcode
            return obj.geometry.transform(srid=your_srid)
    

    At the model level (make the database do the transformation):

    in your view:

    from django.contrib.gis.db.models.functions import Transform
    TARGET_SRID = 4326
    class LinkView(RetrieveAPIVIew):
        queryset = Link.objects.annotate(transformed=Transform("geometry", TARGET_SRID))
        ...
    

    or (srid passed as path component in url):

    from django.contrib.gis.db.models.functions import Transform
    class LinkView(RetrieveAPIVIew):
        def get_queryset(self):
            return Link.objects.annotate(transformed=Transform("geometry", self.kwargs["srid"])
    

    serializer

    class LinkWithGeometrySerializer(serializers.ModelSerializer):
        geometry = serializers.GeometryField(source='transformed') # [1]
        class Meta:
            model = Link
            fields = ['link_type', 'geometry',]
    

    [1] https://github.com/openwisp/django-rest-framework-gis/blob/master/rest_framework_gis/fields.py#L13