openwisp / django-rest-framework-gis

Geographic add-ons for Django REST Framework. Maintained by the OpenWISP Project.
http://openwisp.org
MIT License
1.08k stars 201 forks source link

Set geo_field to a geo_field from a linked model #49

Closed achraibi closed 9 years ago

achraibi commented 9 years ago

Given the following models, is there a way to serialize MainModel as Geojson by specifying the geo_field attribute from the linked GeoModel ?

class GeoModel(models.Model):
    point = models.PointField()
    objects = models.GeoManager()

class MainModel(models.Model):
    geo_model = models.ForeignKey(GeoModel)

Willing to help contributing if some insight about implementation could be shared. Thanks

nemesifier commented 9 years ago

Hi @achraibi,

I think you could try to create a property on MainModel.

Something like:

class MainModel(models.Model):
    geo_model = models.ForeignKey(GeoModel)

    @property
    def point(self):
        return self.geo_model.point

Try this and let us know if it works.

achraibi commented 9 years ago

Hi @nemesisdesign , well this returns empty geometry

nemesifier commented 9 years ago

I see, the serializer most probably needs a real field to work.

You might need to patch drf-gis to achieve what you want.

If you find a solution that is simple enough we can think about merging it.

achraibi commented 9 years ago

Hi @nemesisdesign ,current restframework API combined with django-rest-framework-gis actually allows that use case by using a @property and explicitly adding the correspondant GeometryField to the serializer:

#models.py
from django.contrib.gis.db import models

class GeoModel(models.Model):
    point = models.PointField()
    objects = models.GeoManager()

class MainModel(models.Model):
    geo_model = models.ForeignKey(GeoModel)

    @property
    def point(self):
        return self.geo_model.point

#serializers.py
from rest_framework_gis.fields import GeometryField
from rest_framework_gis.serializers import GeoFeatureModelSerializer

class MainModelSerializer(GeoFeatureModelSerializer):
    point = GeometryField()

    class Meta:
        model = Lot
        geo_field = 'point'

The issue is thus not an issue :)

nemesifier commented 9 years ago

@achraibi that was exactly what I meant in my first answer. Very glad that you figured it out!

sammy88888888 commented 9 years ago

Hi, sorry to keep this going, but this doesn't seem to be working for me, or is it maybe because I am using ManyToManyField. Here's my code.

#models.py
class Location(models.Model):
    city = models.CharField(max_length=200)
    point = models.PointField(srid=4326)
    objects = models.GeoManager()

class Article(models.Model):
    locations = models.ManyToManyField(Location)
    article_title = models.CharField(max_length=200)

    @property
    def point(self):
    return self.locations.point

#serializers.py
class ArticleSerializer(GeoFeatureModelSerializer):
point = GeometryField()

class Meta:
    model = Article
    geo_field = "point"
    id_field = False
    fields = ('pub_date', 'point',)

And the error:

Got AttributeError when attempting to get a value for field `point` on serializer `ArticleSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Article`     instance.
Original exception text was: 'ManyRelatedManager' object has no attribute 'point'.

Thanks in advance for any help!

achraibi commented 9 years ago

Hi @sammy88888888, the error is in the point property. Article has many Locations and each of the locations has a point. If you want to serialize an Article with one point, the property should pick the relevant Location object for the current article, and return its geometry field. There might be something unclear in your design, at least this is what the property tells at first sight.

sammy88888888 commented 9 years ago

Possibly, although I'm struggling to see where it is. When I write my serializer like this:

class ArticleSerializer(GeoFeatureModelSerializer):
    locations = serializers.StringRelatedField(many=True)   

    class Meta:
        model = Article
        geo_field = "locations"
        id_field = False
        fields = ('pub_date', 'locations',)

I get:

{  
    "type":"FeatureCollection",
    "features":[  
        {  
            "type":"Feature",
            "geometry":[  
                "SRID=4326;POINT (-2.2003379561186454 53.4831642374137104)"
            ],
            "properties":{  
                "pub_date":"2015-04-06T20:38:59Z"
            }
        }    
    ]
}

I've been grappling with this for ages now. Close but still not quite there...