Search code examples
pythondjangogeojsondjango-serializer

Passing a model function to geojson serializer in GeoDjango


Problem description

Ok, I am trying to add a function defined inside a model (called Highway) to the HttpResponse of the model (Highway) after serializing with geojson serializer without success.

I'm trying to find a solution by going through the source code as no errors are passed and the property does not appear in the HttpResponse. I might however be complicating things and hopefully can get another eyes on this. I'm open to other suggestions, maybe to update the Highway each time a Location is added/modified.

The item appears correctly when passing it to the admin site and all other fields (not shown below) work as intended.

PS. I'm quite new to the whole Django system. Thank you!

Django version: 2.1

Relevant links:

  1. https://docs.djangoproject.com/en/2.1/ref/contrib/gis/serializers/
  2. https://github.com/django/django/blob/master/django/contrib/gis/serializers/geojson.py

Minified code

geom.models.py

class Highway(models.Model):

    name = models.CharField(max_length=50, unique=True)
    length = models.IntegerField("Length in meters")
    mline = models.MultiLineStringField("Geometry", srid=4326)

    def cameras_per_km(self):
        #THIS IS THE FUNCTION I AM TRYING TO SEND TO GEOJSON SERIALIZER
        count = self.location_set.filter(location__icontains="camera").count()
        return round(count/(self.length/1000),1)
    cameras_per_km.short_description = "Cameras/km"


class Location(models.Model):

    location = models.CharField(max_length=30, unique=True)
    highway = models.ForeignKey(Highway, null=True, on_delete=models.SET_NULL)
    point = models.PointField()

geom.admin.py (when passing the func to list_display the item appears correclty in admin)

class HighwayAdmin(LeafletGeoAdmin):
    list_display = ('name', 'cameras_per_km')

admin.site.register(
    Highway, 
    HighwayAdmin, 
)

geom.views.py (this doesn't)

def geojson_highway_all(request):

    geojsonformat = serialize('geojson', 
          Highway.objects.all(),
          geometry_field='mline',
          fields = (
            'pk',
            'cameras_per_km'  # <-- I want this to show
          )
    )

    return HttpResponse(geojsonformat)

geom.urls.py

from django.urls import path
from . import views

app_name = 'geom'

urlpatterns = [
    path('highways.geojson', views.geojson_highway_all, name='highways.geojson'),
]

Solution

  • Update: I (Anton vBR) have now rewritten this answer completely but think @ruddra deserves some credit. I am however open for alternative solutions. Hopefullly this answer can helps someone out in the future.


    Create a new Serializer based on geojson serializer

    geom.views.py

    from django.contrib.gis.serializers.geojson import Serializer 
    
    class CustomSerializer(Serializer):
    
        def end_object(self, obj):
            for field in self.selected_fields:
                if field == self.geometry_field or field == 'pk':
                    continue
                elif field in self._current.keys():
                    continue
                else:
                    try:
                        self._current[field] = getattr(obj, field)()
                    except AttributeError:
                        pass
            super(CustomSerializer, self).end_object(obj)
    
    geojsonformat = CustomSerializer().serialize(
          Highway.objects.all(),
          geometry_field='mline',
          fields = (
            'pk',
            'cameras_per_km'
          )