How can I flatten a foreignkey object with django-rest-framework- (gis)

I searched long and far for a solution that was relevant and specific to my problem, but so far I have not found a solution or clear documentation on what I really need to do in order to smooth out relations in order to become compatible with geojson.

This question is almost identical to mine, however, solutions or answers do not solve the problem and still creates invalid GeoJSON.

Related

Problem

I have a model Locationthat contains pointfieldwith SRID = 4326. I also have a model TrainStationthat has a Locationfield as a foreign key for Location. When I serialize TrainStationthrough GeoFeatureModelSerializer, it throws an invalid GeoJSON (see the example below "invalid geojson").

(A valid GeoJSON can, of course, be obtained if I store it somewhere pointfieldin the model TrainStation, but in my case I cannot do this, so I need to smooth it out somehow.)

Question

  • How to achieve a result, for example, the example "Valid GeoJSON" below?

Research

Python, Django, , , , - to_representation(), , , , .

models.py

class Location(models.Model):

    point = models.PointField()

class TrainStation(models.Model):

    location_signature = models.CharField(primary_key=True, max_length=32)
    advertised_location_name = models.CharField(max_length=32)
    country_code = models.ForeignKey(Country)
    county_no = models.ForeignKey(County)
    location = models.ForeignKey(Location, null=True)

serializers.py

class LocationSerializer(ModelSerializer):

    class Meta:
        model = Location
        geo_field = 'point'
        fields = [
            'point',
        ]


class TrainStationSerializer(GeoFeatureModelSerializer):

    location_signature = PrimaryKeyRelatedField(read_only=True)
    location = LocationSerializer(read_only=True)
    country_code = StringRelatedField(read_only=True)
    county_no = StringRelatedField(read_only=True)

    class Meta:
        model = TrainStation
        geo_field = 'location'
        fields = [
            'location_signature',
            'advertised_location_name',
            'country_code',
            'county_no',
        ]

GeoJSON:

http://geojson.io, , .

GeoJSON

{
    "type": "FeatureCollection",
    "features": [
        {
            "id": "Ak",
            "type": "Feature",
            "geometry": {
                "point": {           <------+------ offending lines
                    "type": "Point",        |
                    "coordinates": [        |
                        18.8303462142963,   |
                        68.3486410812835    |
                    ]                       |
                }                    <------+
            },
            "properties": {
                "advertised_location_name": "Abisko Östra",
                "country_code": "Sverige",
                "county_no": "Norrbottens län"
            }
        }
    ]
}

GeoJSON

, .

{
    "type": "FeatureCollection",
    "features": [
        {
            "id": "Ak",
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [
                    18.8303462142963,
                    68.3486410812835
                ]
            },
            "properties": {
                "advertised_location_name": "Abisko Östra",
                "country_code": "Sverige",
                "county_no": "Norrbottens län"
            }
        }
    ]
}
+4
2

:

class LocationSerializer(ModelSerializer):

    def to_representation(self, obj):

        representation = super().to_representation(obj)
        point_representation = representation.pop('point')
        for key in point_representation:
            representation[key] = point_representation[key]

        return representation

    class Meta:
        model = Location
        geo_field = 'point'
        fields = [
            'point',
        ]

GeoJSON:

{
    "type": "FeatureCollection",
    "features": [
        {
            "id": "Ak",
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [
                    18.8303462142963,
                    68.3486410812835
                ]
            },
            "properties": {
                "advertised_location_name": "Abisko Östra",
                "country_code": "Sverige",
                "county_no": "Norrbottens län"
            }
        }
    ]
}

- - , : -)

+1

, , ModelSerializer - , geojson, geojson Serializers django-restframework-gis, , .

, GeoFeatureModelSerializer geo_field, - GeometryField, rest_framework_gis.fields.GeometryField. , , .

  • location.point TrainStationSerializer , . : , drf-gis geo_field, , .

    from rest_framework_gis.fields import GeometryField
    from rest_framework_gis.serializers import GeoFeatureModelSerializer
    
    
    class TrainStationSerializer(GeoFeatureModelSerializer):
    
        location_signature = PrimaryKeyRelatedField(read_only=True)
        country_code = StringRelatedField(read_only=True)
        county_no = StringRelatedField(read_only=True)
    
        class Meta:
            model = TrainStation
            geo_field = 'location__point'
            fields = [
                'location_signature',
                'advertised_location_name',
                'country_code',
                'county_no',
            ]
    
  • fields.GeometryField, drf-gis location.point .

    from rest_framework_gis.fields import GeometryField
    from rest_framework_gis.serializers import GeoFeatureModelSerializer
    
    
    class TrainStationSerializer(GeoFeatureModelSerializer):
    
        location_signature = PrimaryKeyRelatedField(read_only=True)
        location = GeometryField(source='location.point')
        country_code = StringRelatedField(read_only=True)
        county_no = StringRelatedField(read_only=True)
    
        class Meta:
            model = TrainStation
            geo_field = 'location'
            fields = [
                'location_signature',
                'advertised_location_name',
                'country_code',
                'county_no',
            ]
    
  • GeometrySerializerMethodField, drf-gis readme

    from rest_framework_gis.fields import GeometrySerializerMethodField
    from rest_framework_gis.serializers import GeoFeatureModelSerializer
    
    
    class TrainStationSerializer(GeoFeatureModelSerializer):
    
        location_signature = PrimaryKeyRelatedField(read_only=True)
        location = GeometrySerializerMethodField()
        country_code = StringRelatedField(read_only=True)
        county_no = StringRelatedField(read_only=True)
    
        def get_location(self, obj):
            return obj.location.point
    
        class Meta:
            model = TrainStation
            geo_field = 'location'
            fields = [
                'location_signature',
                'advertised_location_name',
                'country_code',
                'county_no',
            ]
    
0

Source: https://habr.com/ru/post/1680536/


All Articles