X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/95045552540ca917d273954ebfa20b47a306bb93..9c5d9a4e77a10b4e60d89d3890e49002bd7f3993:/apps/piston/emitters.py diff --git a/apps/piston/emitters.py b/apps/piston/emitters.py index 1ff0a52da..c2116d22b 100644 --- a/apps/piston/emitters.py +++ b/apps/piston/emitters.py @@ -58,7 +58,7 @@ class Emitter(object): as the methods on the handler. Issue58 says that's no good. """ EMITTERS = { } - RESERVED_FIELDS = set([ 'read', 'update', 'create', + RESERVED_FIELDS = set([ 'read', 'update', 'create', 'delete', 'model', 'anonymous', 'allowed_methods', 'fields', 'exclude' ]) @@ -68,16 +68,16 @@ class Emitter(object): self.handler = handler self.fields = fields self.anonymous = anonymous - + if isinstance(self.data, Exception): raise - + def method_fields(self, handler, fields): if not handler: return { } ret = dict() - + for field in fields - Emitter.RESERVED_FIELDS: t = getattr(handler, str(field), None) @@ -85,13 +85,13 @@ class Emitter(object): ret[field] = t return ret - + 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=()): @@ -99,7 +99,7 @@ class Emitter(object): Dispatch, all types are routed through here. """ ret = None - + if isinstance(thing, QuerySet): ret = _qs(thing, fields=fields) elif isinstance(thing, (tuple, list)): @@ -131,19 +131,19 @@ class Emitter(object): 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 @@ -152,7 +152,7 @@ class Emitter(object): ret = { } handler = self.in_typemapper(type(data), self.anonymous) get_absolute_uri = False - + if handler or fields: v = lambda f: getattr(data, f.attname) @@ -167,26 +167,26 @@ class Emitter(object): 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 not any([ p in met_fields for p in [ f.attname, f.name ]]): if not f.rel: @@ -197,13 +197,13 @@ class Emitter(object): 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)): @@ -225,7 +225,7 @@ class Emitter(object): # using different names. ret[maybe_field] = _any(met_fields[maybe_field](data)) - else: + else: maybe = getattr(data, maybe_field, None) if maybe: if callable(maybe): @@ -242,13 +242,13 @@ class Emitter(object): 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) @@ -259,51 +259,51 @@ class Emitter(object): ret['resource_uri'] = reverser( lambda: (url_id, fields) )() except NoReverseMatch, e: pass - + 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) - + def in_typemapper(self, model, anonymous): for klass, (km, is_anon) in self.typemapper.iteritems(): if model is km and is_anon is anonymous: return klass - + def render(self): """ This super emitter does not implement `render`, this is a job for the specific emitter below. """ raise NotImplementedError("Please implement render.") - + def stream_render(self, request, stream=True): """ Tells our patched middleware not to look @@ -312,7 +312,7 @@ class Emitter(object): more memory friendly for large datasets. """ yield self.render(request) - + @classmethod def get(cls, format): """ @@ -322,19 +322,19 @@ class Emitter(object): return cls.EMITTERS.get(format) raise ValueError("No emitters found for type %s" % format) - + @classmethod def register(cls, name, klass, content_type='text/plain'): """ Register an emitter. - + Parameters:: - `name`: The name of the emitter ('json', 'xml', 'yaml', ...) - `klass`: The emitter class. - `content_type`: The content type to serve response as. """ cls.EMITTERS[name] = (klass, content_type) - + @classmethod def unregister(cls, name): """ @@ -342,7 +342,7 @@ class Emitter(object): want to provide output in one of the built-in emitters. """ return cls.EMITTERS.pop(name, None) - + class XMLEmitter(Emitter): def _to_xml(self, xml, data): if isinstance(data, (list, tuple)): @@ -360,16 +360,16 @@ class XMLEmitter(Emitter): def render(self, request): stream = StringIO.StringIO() - + xml = SimplerXMLGenerator(stream, "utf-8") xml.startDocument() xml.startElement("response", {}) - + self._to_xml(xml, self.construct()) - + xml.endElement("response") xml.endDocument() - + return stream.getvalue() Emitter.register('xml', XMLEmitter, 'text/xml; charset=utf-8') @@ -388,10 +388,10 @@ class JSONEmitter(Emitter): return '%s(%s)' % (cb, seria) return seria - + Emitter.register('json', JSONEmitter, 'application/json; charset=utf-8') Mimer.register(simplejson.loads, ('application/json',)) - + class YAMLEmitter(Emitter): """ YAML emitter, uses `safe_dump` to omit the @@ -410,7 +410,7 @@ class PickleEmitter(Emitter): """ def render(self, request): return pickle.dumps(self.construct()) - + Emitter.register('pickle', PickleEmitter, 'application/python-pickle') """ @@ -437,5 +437,5 @@ class DjangoEmitter(Emitter): response = serializers.serialize(format, self.data, indent=True) return response - + Emitter.register('django', DjangoEmitter, 'text/xml; charset=utf-8')