Created
August 28, 2009 18:37
-
-
Save ingenieroariel/177140 to your computer and use it in GitHub Desktop.
BME piston api for Remco
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# encoding: utf-8 | |
""" | |
emitters.py | |
Created by Ariel Nunez on 2009-05-24. | |
Copyright (c) 2009 Burning Man Earth. All rights reserved. | |
""" | |
from __future__ import generators | |
import types, decimal, types, re, inspect | |
from piston.emitters import JSONEmitter | |
from django.core.serializers.json import DjangoJSONEncoder | |
from django.contrib.gis.geos import fromstr | |
import simplejson | |
from django.db.models.query import QuerySet | |
from django.db.models import Model, permalink | |
from django.utils import simplejson | |
from django.utils.xmlutils import SimplerXMLGenerator | |
from django.utils.encoding import smart_unicode | |
from django.core.serializers.json import DateTimeAwareJSONEncoder | |
from django.http import HttpResponse | |
from django.core import serializers | |
from django.contrib.gis.geos.geometry import GEOSGeometry | |
class GeoJSONEmitter(JSONEmitter): | |
""" | |
GeoJSON emitter, understands timestamps and GIS objects | |
""" | |
def construct(self): | |
""" | |
Recursively serialize a lot of types, and | |
in cases where it doesn't recognize the type, | |
it will fall back to Django's `smart_unicode`. | |
Returns `dict`. | |
""" | |
def _any(thing, fields=()): | |
""" | |
Dispatch, all types are routed through here. | |
""" | |
ret = None | |
if isinstance(thing, QuerySet): | |
ret = _qs(thing, fields=fields) | |
elif isinstance(thing, (tuple, list)): | |
ret = _list(thing) | |
elif isinstance(thing, dict): | |
ret = _dict(thing) | |
elif isinstance(thing, decimal.Decimal): | |
ret = str(thing) | |
elif isinstance(thing, Model): | |
ret = _model(thing, fields=fields) | |
elif isinstance(thing, HttpResponse): | |
raise HttpStatusCode(thing.content, code=thing.status_code) | |
elif isinstance(thing, types.FunctionType): | |
if not inspect.getargspec(thing)[0]: | |
ret = _any(thing()) | |
elif isinstance(thing, GEOSGeometry): | |
ret = thing.geojson | |
else: | |
ret = smart_unicode(thing, strings_only=True) | |
return ret | |
def _fk(data, field): | |
""" | |
Foreign keys. | |
""" | |
return _any(getattr(data, field.name)) | |
def _related(data, fields=()): | |
""" | |
Foreign keys. | |
""" | |
return [ _model(m, fields) for m in data.iterator() ] | |
def _m2m(data, field, fields=()): | |
""" | |
Many to many (re-route to `_model`.) | |
""" | |
return [ _model(m, fields) for m in getattr(data, field.name).iterator() ] | |
def _model(data, fields=()): | |
""" | |
Models. Will respect the `fields` and/or | |
`exclude` on the handler (see `typemapper`.) | |
""" | |
ret = { } | |
handler = self.in_typemapper(type(data), self.anonymous) | |
get_absolute_uri = False | |
if handler or fields: | |
v = lambda f: getattr(data, f.attname) | |
if not fields: | |
""" | |
Fields was not specified, try to find teh correct | |
version in the typemapper we were sent. | |
""" | |
mapped = self.in_typemapper(type(data), self.anonymous) | |
get_fields = set(mapped.fields) | |
exclude_fields = set(mapped.exclude).difference(get_fields) | |
if 'absolute_uri' in get_fields: | |
get_absolute_uri = True | |
if not get_fields: | |
get_fields = set([ f.attname.replace("_id", "", 1) | |
for f in data._meta.fields ]) | |
# sets can be negated. | |
for exclude in exclude_fields: | |
if isinstance(exclude, basestring): | |
get_fields.discard(exclude) | |
elif isinstance(exclude, re._pattern_type): | |
for field in get_fields.copy(): | |
if exclude.match(field): | |
get_fields.discard(field) | |
else: | |
get_fields = set(fields) | |
met_fields = self.method_fields(handler, get_fields) | |
for f in data._meta.local_fields: | |
if f.serialize and f.attname not in met_fields: | |
if not f.rel: | |
if f.attname in get_fields: | |
ret[f.attname] = _any(v(f)) | |
get_fields.remove(f.attname) | |
else: | |
if f.attname[:-3] in get_fields: | |
ret[f.name] = _fk(data, f) | |
get_fields.remove(f.name) | |
for mf in data._meta.many_to_many: | |
if mf.serialize and mf.attname not in met_fields: | |
if mf.attname in get_fields: | |
ret[mf.name] = _m2m(data, mf) | |
get_fields.remove(mf.name) | |
# try to get the remainder of fields | |
for maybe_field in get_fields: | |
if isinstance(maybe_field, (list, tuple)): | |
model, fields = maybe_field | |
inst = getattr(data, model, None) | |
if inst: | |
if hasattr(inst, 'all'): | |
ret[model] = _related(inst, fields) | |
elif callable(inst): | |
if len(inspect.getargspec(inst)[0]) == 1: | |
ret[model] = _any(inst(), fields) | |
else: | |
ret[model] = _model(inst, fields) | |
elif maybe_field in met_fields: | |
# Overriding normal field which has a "resource method" | |
# so you can alter the contents of certain fields without | |
# using different names. | |
ret[maybe_field] = _any(met_fields[maybe_field](data)) | |
else: | |
maybe = getattr(data, maybe_field, None) | |
if maybe: | |
if isinstance(maybe, (int, basestring)): | |
ret[maybe_field] = _any(maybe) | |
elif callable(maybe): | |
if len(inspect.getargspec(maybe)[0]) == 1: | |
ret[maybe_field] = _any(maybe()) | |
else: | |
handler_f = getattr(handler or self.handler, maybe_field, None) | |
if handler_f: | |
ret[maybe_field] = _any(handler_f(data)) | |
else: | |
for f in data._meta.fields: | |
ret[f.attname] = _any(getattr(data, f.attname)) | |
fields = dir(data.__class__) + ret.keys() | |
add_ons = [k for k in dir(data) if k not in fields] | |
for k in add_ons: | |
ret[k] = _any(getattr(data, k)) | |
# resouce uri | |
if self.in_typemapper(type(data), self.anonymous): | |
handler = self.in_typemapper(type(data), self.anonymous) | |
if hasattr(handler, 'resource_uri'): | |
url_id, fields = handler.resource_uri() | |
ret['resource_uri'] = permalink( lambda: (url_id, | |
(getattr(data, f) for f in fields) ) )() | |
if hasattr(data, 'get_api_url') and 'resource_uri' not in ret: | |
try: ret['resource_uri'] = data.get_api_url() | |
except: pass | |
# absolute uri | |
if hasattr(data, 'get_absolute_url') and get_absolute_uri: | |
try: ret['absolute_uri'] = data.get_absolute_url() | |
except: pass | |
return ret | |
def _qs(data, fields=()): | |
""" | |
Querysets. | |
""" | |
return [ _any(v, fields) for v in data ] | |
def _list(data): | |
""" | |
Lists. | |
""" | |
return [ _any(v) for v in data ] | |
def _dict(data): | |
""" | |
Dictionaries. | |
""" | |
return dict([ (k, _any(v)) for k, v in data.iteritems() ]) | |
# Kickstart the seralizin'. | |
return _any(self.data, self.fields) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
from piston.handler import BaseHandler, AnonymousBaseHandler | |
from piston.emitters import Emitter, JSONEmitter | |
from brc.models import * | |
from api.emitters import GeoJSONEmitter | |
from swingtime.models import Event, Occurrence | |
import time | |
JSONEmitter.unregister('json') | |
Emitter.register('json', GeoJSONEmitter, content_type='text/javascript; charset=utf-8') | |
art_fields = ('id', 'name', ('year', ('id','year')), 'slug', 'artist', 'description', 'url', 'contact_email', 'location_point', 'location_poly', 'circular_street', 'time_address') | |
event_fields = ('id', 'title','description', 'print_description', ('year', ('id','year')), 'slug', 'event_type', ('hosted_by_camp', ('id','name')), ('located_at_art', ('id','name')), 'other_location', 'check_location', 'url', 'location_point', 'location_track', 'all_day', ('occurrence_set', ('start_time', 'end_time'))) | |
camp_fields = ('id', ('year', ('id','year')), 'name', 'description', 'type', 'start_date_time', 'end_date_time', 'duration', 'repeats', 'hosted_by_camp', 'located_at_art', 'url', 'contact_email') | |
cstreet_fields = ('id', ('year', ('id','year')), 'name', 'order', 'width', 'distance_from_center', 'street_line') | |
tstreet_fields = ('id', ('year', ('id','year')), 'hour', 'minute', 'name', 'width', 'street_line') | |
infrastructure_fields = ('id', ('year', ('id','year')), 'name', 'location_point', 'location_line', 'location_poly', 'location_multigeom', 'tags') | |
year_fields = ('id', 'location', 'location_point', 'participants', 'theme') | |
user_fields = ('id', 'username', 'first_name', 'last_name', 'active') | |
class AnonymousArtInstallationHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = ArtInstallation | |
fields = art_fields | |
def read(self, request, year_year=None, art_id=None): | |
base = ArtInstallation.objects.filter() | |
if(year_year): | |
year = Year.objects.get(year=year_year) | |
if(art_id): | |
art = ArtInstallation.objects.filter(year=year,id=art_id) | |
else: | |
art = ArtInstallation.objects.filter(year=year) | |
return art | |
else: | |
return base.all() | |
class ArtInstallationHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = ArtInstallation | |
fields = art_fields | |
anonymous = AnonymousArtInstallationHandler | |
class AnonymousPlayaEventHandler(AnonymousBaseHandler): | |
allow_methods = ('GET',) | |
model = PlayaEvent | |
fields = event_fields | |
def read(self, request, year_year=None, playa_event_id=None): | |
base = PlayaEvent.objects.filter(moderation='A', list_online=True) | |
if(year_year): | |
year = Year.objects.get(year=year_year) | |
if(playa_event_id): | |
events = PlayaEvent.objects.filter(year=year,id=playa_event_id) | |
else: | |
if(request.GET.get('start_time') and request.GET.get('end_time')): | |
event_list = Occurrence.objects.filter(start_time__gte=request.GET.get('start_time'), end_time__lte=request.GET.get('end_time')).values_list('event', flat=True) | |
events = PlayaEvent.objects.filter(id__in=event_list) | |
elif(request.GET.get('start_time')): | |
event_list = Occurrence.objects.filter(start_time__gte=request.GET.get('start_time')).values_list('event', flat=True) | |
events = PlayaEvent.objects.filter(id__in=event_list) | |
elif(request.GET.get('end_time')): | |
event_list = Occurrence.objects.filter(end_time__lte=request.GET.get('end_time')).values_list('event', flat=True) | |
events = PlayaEvent.objects.filter(id__in=event_list) | |
else: | |
events = PlayaEvent.objects.filter(year=year) | |
return events | |
else: | |
return base.all() | |
class PlayaEventHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = PlayaEvent | |
anonymous = AnonymousPlayaEventHandler | |
fields = event_fields | |
class AnonymousThemeCampHandler(AnonymousBaseHandler): | |
allow_methods = ('GET',) | |
model = ThemeCamp | |
fields = camp_fields | |
def read(self, request, year_year=None, camp_id=None): | |
base = ThemeCamp.objects.filter() | |
if(year_year): | |
year = Year.objects.get(year=year_year) | |
if(camp_id): | |
camp = ThemeCamp.objects.filter(year=year,id=camp_id) | |
else: | |
camp = ThemeCamp.objects.filter(year=year) | |
return camp | |
else: | |
return base.all() | |
class ThemeCampHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = ThemeCamp | |
fields = camp_fields | |
anonymous = AnonymousThemeCampHandler | |
class AnonymousCircularStreetHandler(AnonymousBaseHandler): | |
allow_methods = ('GET',) | |
model = CircularStreet | |
fields = cstreet_fields | |
def read(self, request, year_year=None): | |
base = CircularStreet.objects.filter() | |
if(year_year): | |
year = Year.objects.get(year=year_year) | |
cstreet = CircularStreet.objects.filter(year=year) | |
return cstreet | |
else: | |
return base.all() | |
class CircularStreetHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = CircularStreet | |
fields = cstreet_fields | |
anonymous = AnonymousCircularStreetHandler | |
class AnonymousTimeStreetHandler(AnonymousBaseHandler): | |
allow_methods = ('GET',) | |
model = TimeStreet | |
fields = tstreet_fields | |
def read(self, request, year_year=None): | |
base = TimeStreet.objects.filter() | |
if(year_year): | |
year = Year.objects.get(year=year_year) | |
tstreet = TimeStreet.objects.filter(year=year) | |
return tstreet | |
else: | |
return base.all() | |
class TimeStreetHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = TimeStreet | |
fields = tstreet_fields | |
anonymous = AnonymousTimeStreetHandler | |
class AnonymousInfrastructureHandler(AnonymousBaseHandler): | |
allow_methods = ('GET',) | |
model = Infrastructure | |
fields = infrastructure_fields | |
def read(self, request, year_year=None): | |
base = Infrastructure.objects.filter() | |
if(year_year): | |
year = Year.objects.get(year=year_year) | |
infrastructure = Infrastructure.objects.filter(year=year) | |
return infrastructure | |
else: | |
return base.all() | |
class InfrastructureHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = Infrastructure | |
fields = infrastructure_fields | |
anonymous = AnonymousInfrastructureHandler | |
class AnonymousYearHandler(AnonymousBaseHandler): | |
allow_methods = ('GET',) | |
model = Year | |
fields = year_fields | |
class YearHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = Year | |
fields = year_fields | |
anonymous = AnonymousYearHandler | |
class UserHandler(BaseHandler): | |
allow_methods = ('GET',) | |
model = User | |
fields = user_fields |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.conf.urls.defaults import * | |
from piston.resource import Resource | |
from api.handlers import * | |
from piston.authentication import OAuthAuthentication | |
auth = OAuthAuthentication() | |
year_handler = Resource(YearHandler, authentication=auth) | |
camp_handler = Resource(ThemeCampHandler, authentication=auth) | |
art_handler = Resource(ArtInstallationHandler, authentication=auth) | |
event_handler = Resource(PlayaEventHandler, authentication=auth) | |
user_handler = Resource(UserHandler, authentication=auth) | |
cstreet_handler = Resource(CircularStreetHandler, authentication=auth) | |
tstreet_handler = Resource(TimeStreetHandler, authentication=auth) | |
infrastructure_handler = Resource(InfrastructureHandler, authentication=auth) | |
urlpatterns = patterns('', | |
url(r'^user/', user_handler), | |
url(r'^year/', year_handler), | |
url(r'^(?P<year_year>\d{4})/camp/(?P<camp_id>\d+)/$', camp_handler), | |
url(r'^(?P<year_year>\d{4})/camp/', camp_handler), | |
url(r'^(?P<year_year>\d{4})/art/(?P<art_id>\d+)/$', art_handler), | |
url(r'^(?P<year_year>\d{4})/art/', art_handler), | |
url(r'^(?P<year_year>\d{4})/event/(?P<playa_event_id>\d+)/$', event_handler), | |
url(r'^(?P<year_year>\d{4})/event/', event_handler), | |
url(r'^(?P<year_year>\d{4})/cstreet/', cstreet_handler), | |
url(r'^(?P<year_year>\d{4})/tstreet/', tstreet_handler), | |
url(r'^(?P<year_year>\d{4})/infrastructure/', infrastructure_handler), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment