Skip to content

Instantly share code, notes, and snippets.

@cspanring
Created February 8, 2012 18:25
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cspanring/1771937 to your computer and use it in GitHub Desktop.
Save cspanring/1771937 to your computer and use it in GitHub Desktop.
Add GeoJSON support for geometry fields in django-tastypie
# Shamelessly stolen from https://github.com/newsapps/django-boundaryservice/blob/master/boundaryservice/tastyhacks.py
from django.contrib.gis.db.models import GeometryField
from django.utils import simplejson
from tastypie.bundle import Bundle
from tastypie.fields import ApiField, CharField
from tastypie.resources import ModelResource
class GeometryApiField(ApiField):
"""
Custom ApiField for dealing with data from GeometryFields (by serializing them as GeoJSON).
"""
dehydrated_type = 'geometry'
help_text = 'Geometry data.'
def hydrate(self, bundle):
value = super(GeometryApiField, self).hydrate(bundle)
if value is None:
return value
return simplejson.dumps(value)
def dehydrate(self, obj):
return self.convert(super(GeometryApiField, self).dehydrate(obj))
def convert(self, value):
if value is None:
return None
if isinstance(value, dict):
return value
# Get ready-made geojson serialization and then convert it _back_ to a Python object
# so that Tastypie can serialize it as part of the bundle
return simplejson.loads(value.geojson)
class GeoResource(ModelResource):
"""
ModelResource subclass that handles geometry fields as GeoJSON.
"""
@classmethod
def api_field_from_django_field(cls, f, default=CharField):
"""
Overrides default field handling to support custom GeometryApiField.
"""
if isinstance(f, GeometryField):
return GeometryApiField
return super(GeoResource, cls).api_field_from_django_field(f, default)
@dgerzo
Copy link

dgerzo commented Feb 26, 2012

I am trying to use this code, it works fine, however do you have an idea why the coordinates are getting stripped down to 10 characters?

@dgerzo
Copy link

dgerzo commented Feb 26, 2012

Also, how do I POST/PUT/PATCH to the GeometryApiField? I tried the same data that was returned by GET, but I am getting ``cannot set Order GeometryProxy with value of type: dict` exception

@dgerzo
Copy link

dgerzo commented Feb 26, 2012

so, whoever needs to POST/PUT/PATCH on GeometryApiField, add the following method into the GeometryApiField:

    def hydrate(self, bundle):
        value = super(GeometryApiField, self).hydrate(bundle)
        return simplejson.dumps(value)

@cspanring
Copy link
Author

excellent, thanks! will try it in an upcoming project.

@dgerzo
Copy link

dgerzo commented Feb 29, 2012

here's a little bugfix for a case when value is None:

    def hydrate(self, bundle):
        value = super(GeometryApiField, self).hydrate(bundle)
        if value is None:
            return value
        return simplejson.dumps(value)

@philipn
Copy link

philipn commented Mar 3, 2012

This seems to work great! I've started a tastypie branch to work on geo-related stuff. The idea is you'd be able to do something like:

from tastypie.contrib.gis.resources import ModelResource

class MyResource(ModelResource):
 ...

which would be more in line with how Django handles gis stuff in general. I think this should be included in tastypie, but if not we can break off into a separate tastypie-contrib repository.

@cspanring
Copy link
Author

this seems like a good approach. did you discuss this with tastypie maintainers or post a pull request?

@philipn
Copy link

philipn commented Mar 6, 2012

I will issue a pull request once I'm satisfied that my branch is working right. And once I have tests + docs :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment