mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 19:14:01 +03:00
emitters -> renderers
This commit is contained in:
parent
ad552107ff
commit
93aa065fa9
|
@ -233,8 +233,8 @@ class RequestMixin(object):
|
|||
|
||||
@property
|
||||
def default_parser(self):
|
||||
"""Return the view's most preffered emitter.
|
||||
(This has no behavioural effect, but is may be used by documenting emitters)"""
|
||||
"""Return the view's most preffered renderer.
|
||||
(This has no behavioural effect, but is may be used by documenting renderers)"""
|
||||
return self.parsers[0]
|
||||
|
||||
|
||||
|
@ -249,7 +249,7 @@ class RequestMixin(object):
|
|||
########## ResponseMixin ##########
|
||||
|
||||
class ResponseMixin(object):
|
||||
"""Adds behaviour for pluggable Emitters to a :class:`.Resource` or Django :class:`View`. class.
|
||||
"""Adds behaviour for pluggable Renderers to a :class:`.Resource` or Django :class:`View`. class.
|
||||
|
||||
Default behaviour is to use standard HTTP Accept header content negotiation.
|
||||
Also supports overidding the content type by specifying an _accept= parameter in the URL.
|
||||
|
@ -260,7 +260,7 @@ class ResponseMixin(object):
|
|||
|
||||
#request = None
|
||||
#response = None
|
||||
emitters = ()
|
||||
renderers = ()
|
||||
|
||||
#def render_to_response(self, obj):
|
||||
# if isinstance(obj, Response):
|
||||
|
@ -285,21 +285,21 @@ class ResponseMixin(object):
|
|||
# return content
|
||||
|
||||
|
||||
def emit(self, response):
|
||||
def render(self, response):
|
||||
"""Takes a :class:`Response` object and returns a Django :class:`HttpResponse`."""
|
||||
self.response = response
|
||||
|
||||
try:
|
||||
emitter = self._determine_emitter(self.request)
|
||||
renderer = self._determine_renderer(self.request)
|
||||
except ErrorResponse, exc:
|
||||
emitter = self.default_emitter
|
||||
renderer = self.default_renderer
|
||||
response = exc.response
|
||||
|
||||
# Serialize the response content
|
||||
if response.has_content_body:
|
||||
content = emitter(self).emit(output=response.cleaned_content)
|
||||
content = renderer(self).render(output=response.cleaned_content)
|
||||
else:
|
||||
content = emitter(self).emit()
|
||||
content = renderer(self).render()
|
||||
|
||||
# Munge DELETE Response code to allow us to return content
|
||||
# (Do this *after* we've rendered the template so that we include the normal deletion response code in the output)
|
||||
|
@ -307,16 +307,16 @@ class ResponseMixin(object):
|
|||
response.status = 200
|
||||
|
||||
# Build the HTTP Response
|
||||
# TODO: Check if emitter.mimetype is underspecified, or if a content-type header has been set
|
||||
resp = HttpResponse(content, mimetype=emitter.media_type, status=response.status)
|
||||
# TODO: Check if renderer.mimetype is underspecified, or if a content-type header has been set
|
||||
resp = HttpResponse(content, mimetype=renderer.media_type, status=response.status)
|
||||
for (key, val) in response.headers.items():
|
||||
resp[key] = val
|
||||
|
||||
return resp
|
||||
|
||||
|
||||
def _determine_emitter(self, request):
|
||||
"""Return the appropriate emitter for the output, given the client's 'Accept' header,
|
||||
def _determine_renderer(self, request):
|
||||
"""Return the appropriate renderer for the output, given the client's 'Accept' header,
|
||||
and the content types that this Resource knows how to serve.
|
||||
|
||||
See: RFC 2616, Section 14 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"""
|
||||
|
@ -333,7 +333,7 @@ class ResponseMixin(object):
|
|||
accept_list = request.META["HTTP_ACCEPT"].split(',')
|
||||
else:
|
||||
# No accept header specified
|
||||
return self.default_emitter
|
||||
return self.default_renderer
|
||||
|
||||
# Parse the accept header into a dict of {qvalue: set of media types}
|
||||
# We ignore mietype parameters
|
||||
|
@ -363,34 +363,34 @@ class ResponseMixin(object):
|
|||
|
||||
for accept_set in accept_sets:
|
||||
# Return any exact match
|
||||
for emitter in self.emitters:
|
||||
if emitter.media_type in accept_set:
|
||||
return emitter
|
||||
for renderer in self.renderers:
|
||||
if renderer.media_type in accept_set:
|
||||
return renderer
|
||||
|
||||
# Return any subtype match
|
||||
for emitter in self.emitters:
|
||||
if emitter.media_type.split('/')[0] + '/*' in accept_set:
|
||||
return emitter
|
||||
for renderer in self.renderers:
|
||||
if renderer.media_type.split('/')[0] + '/*' in accept_set:
|
||||
return renderer
|
||||
|
||||
# Return default
|
||||
if '*/*' in accept_set:
|
||||
return self.default_emitter
|
||||
return self.default_renderer
|
||||
|
||||
|
||||
raise ErrorResponse(status.HTTP_406_NOT_ACCEPTABLE,
|
||||
{'detail': 'Could not satisfy the client\'s Accept header',
|
||||
'available_types': self.emitted_media_types})
|
||||
'available_types': self.renderted_media_types})
|
||||
|
||||
@property
|
||||
def emitted_media_types(self):
|
||||
"""Return an list of all the media types that this resource can emit."""
|
||||
return [emitter.media_type for emitter in self.emitters]
|
||||
def renderted_media_types(self):
|
||||
"""Return an list of all the media types that this resource can render."""
|
||||
return [renderer.media_type for renderer in self.renderers]
|
||||
|
||||
@property
|
||||
def default_emitter(self):
|
||||
"""Return the resource's most prefered emitter.
|
||||
(This emitter is used if the client does not send and Accept: header, or sends Accept: */*)"""
|
||||
return self.emitters[0]
|
||||
def default_renderer(self):
|
||||
"""Return the resource's most prefered renderer.
|
||||
(This renderer is used if the client does not send and Accept: header, or sends Accept: */*)"""
|
||||
return self.renderers[0]
|
||||
|
||||
|
||||
########## Auth Mixin ##########
|
||||
|
|
|
@ -49,7 +49,7 @@ class ModelResource(Resource):
|
|||
|
||||
|
||||
#def get_form(self, content=None):
|
||||
# """Return a form that may be used in validation and/or rendering an html emitter"""
|
||||
# """Return a form that may be used in validation and/or rendering an html renderer"""
|
||||
# if self.form:
|
||||
# return super(self.__class__, self).get_form(content)
|
||||
#
|
||||
|
@ -121,8 +121,8 @@ class ModelResource(Resource):
|
|||
elif inspect.isfunction(thing):
|
||||
if not inspect.getargspec(thing)[0]:
|
||||
ret = _any(thing())
|
||||
elif hasattr(thing, '__emittable__'):
|
||||
f = thing.__emittable__
|
||||
elif hasattr(thing, '__rendertable__'):
|
||||
f = thing.__rendertable__
|
||||
if inspect.ismethod(f) and len(inspect.getargspec(f)[0]) == 1:
|
||||
ret = _any(f())
|
||||
else:
|
||||
|
|
|
@ -4,13 +4,13 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
from djangorestframework.compat import View
|
||||
from djangorestframework.response import Response, ErrorResponse
|
||||
from djangorestframework.mixins import RequestMixin, ResponseMixin, AuthMixin
|
||||
from djangorestframework import emitters, parsers, authenticators, permissions, validators, status
|
||||
from djangorestframework import renderers, parsers, authenticators, permissions, validators, status
|
||||
|
||||
|
||||
# TODO: Figure how out references and named urls need to work nicely
|
||||
# TODO: POST on existing 404 URL, PUT on existing 404 URL
|
||||
#
|
||||
# NEXT: Exceptions on func() -> 500, tracebacks emitted if settings.DEBUG
|
||||
# NEXT: Exceptions on func() -> 500, tracebacks renderted if settings.DEBUG
|
||||
|
||||
__all__ = ['Resource']
|
||||
|
||||
|
@ -21,12 +21,12 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
|
|||
|
||||
http_method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace', 'patch']
|
||||
|
||||
# List of emitters the resource can serialize the response with, ordered by preference.
|
||||
emitters = ( emitters.JSONEmitter,
|
||||
emitters.DocumentingHTMLEmitter,
|
||||
emitters.DocumentingXHTMLEmitter,
|
||||
emitters.DocumentingPlainTextEmitter,
|
||||
emitters.XMLEmitter )
|
||||
# List of renderers the resource can serialize the response with, ordered by preference.
|
||||
renderers = ( renderers.JSONRenderer,
|
||||
renderers.DocumentingHTMLRenderer,
|
||||
renderers.DocumentingXHTMLRenderer,
|
||||
renderers.DocumentingPlainTextRenderer,
|
||||
renderers.XMLRenderer )
|
||||
|
||||
# List of parsers the resource can parse the request with.
|
||||
parsers = ( parsers.JSONParser,
|
||||
|
@ -48,7 +48,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
|
|||
|
||||
# Allow name and description for the Resource to be set explicitly,
|
||||
# overiding the default classname/docstring behaviour.
|
||||
# These are used for documentation in the standard html and text emitters.
|
||||
# These are used for documentation in the standard html and text renderers.
|
||||
name = None
|
||||
description = None
|
||||
|
||||
|
@ -69,7 +69,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
|
|||
Eg filter complex objects that cannot be serialized by json/xml/etc into basic objects that can.
|
||||
|
||||
TODO: This is going to be removed. I think that the 'fields' behaviour is going to move into
|
||||
the EmitterMixin and Emitter classes."""
|
||||
the RendererMixin and Renderer classes."""
|
||||
return data
|
||||
|
||||
|
||||
|
@ -123,7 +123,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View):
|
|||
response.headers['Allow'] = ', '.join(self.allowed_methods)
|
||||
response.headers['Vary'] = 'Authenticate, Accept'
|
||||
|
||||
return self.emit(response)
|
||||
return self.render(response)
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
|
|
@ -28,7 +28,7 @@ urlpatterns = patterns('',
|
|||
|
||||
|
||||
class BreadcrumbTests(TestCase):
|
||||
"""Tests the breadcrumb functionality used by the HTML emitter."""
|
||||
"""Tests the breadcrumb functionality used by the HTML renderer."""
|
||||
|
||||
urls = 'djangorestframework.tests.breadcrumbs'
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ def xml2dict(input):
|
|||
|
||||
|
||||
# Piston:
|
||||
class XMLEmitter():
|
||||
class XMLRenderer():
|
||||
def _to_xml(self, xml, data):
|
||||
if isinstance(data, (list, tuple)):
|
||||
for item in data:
|
||||
|
@ -156,4 +156,4 @@ class XMLEmitter():
|
|||
return stream.getvalue()
|
||||
|
||||
def dict2xml(input):
|
||||
return XMLEmitter().dict2xml(input)
|
||||
return XMLRenderer().dict2xml(input)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from djangorestframework.compat import View # Use Django 1.3's django.views.generic.View, or fall back to a clone of that if Django < 1.3
|
||||
from djangorestframework.mixins import ResponseMixin
|
||||
from djangorestframework.emitters import DEFAULT_EMITTERS
|
||||
from djangorestframework.renderers import DEFAULT_RENDERERS
|
||||
from djangorestframework.response import Response
|
||||
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
@ -9,8 +9,8 @@ from django.core.urlresolvers import reverse
|
|||
|
||||
class ExampleView(ResponseMixin, View):
|
||||
"""An example view using Django 1.3's class based views.
|
||||
Uses djangorestframework's EmitterMixin to provide support for multiple output formats."""
|
||||
emitters = DEFAULT_EMITTERS
|
||||
Uses djangorestframework's RendererMixin to provide support for multiple output formats."""
|
||||
renderers = DEFAULT_RENDERERS
|
||||
|
||||
def get(self, request):
|
||||
response = Response(200, {'description': 'Some example content',
|
||||
|
|
|
@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse
|
|||
|
||||
from djangorestframework.resource import Resource
|
||||
from djangorestframework.response import Response
|
||||
from djangorestframework.emitters import BaseEmitter
|
||||
from djangorestframework.renderers import BaseRenderer
|
||||
from djangorestframework import status
|
||||
|
||||
from pygments.formatters import HtmlFormatter
|
||||
|
@ -32,8 +32,8 @@ def remove_oldest_files(dir, max_files):
|
|||
[os.remove(path) for path in list_dir_sorted_by_ctime(dir)[max_files:]]
|
||||
|
||||
|
||||
class HTMLEmitter(BaseEmitter):
|
||||
"""Basic emitter which just returns the content without any further serialization."""
|
||||
class HTMLRenderer(BaseRenderer):
|
||||
"""Basic renderer which just returns the content without any further serialization."""
|
||||
media_type = 'text/html'
|
||||
|
||||
|
||||
|
@ -68,8 +68,8 @@ class PygmentsRoot(Resource):
|
|||
|
||||
class PygmentsInstance(Resource):
|
||||
"""Simply return the stored highlighted HTML file with the correct mime type.
|
||||
This Resource only emits HTML and uses a standard HTML emitter rather than the emitters.DocumentingHTMLEmitter class."""
|
||||
emitters = (HTMLEmitter,)
|
||||
This Resource only emits HTML and uses a standard HTML renderer rather than the renderers.DocumentingHTMLRenderer class."""
|
||||
renderers = (HTMLRenderer,)
|
||||
|
||||
def get(self, request, unique_id):
|
||||
"""Return the highlighted snippet."""
|
||||
|
|
|
@ -11,14 +11,14 @@ class Sandbox(Resource):
|
|||
|
||||
All the example APIs allow anonymous access, and can be navigated either through the browser or from the command line...
|
||||
|
||||
bash: curl -X GET http://api.django-rest-framework.org/ # (Use default emitter)
|
||||
bash: curl -X GET http://api.django-rest-framework.org/ -H 'Accept: text/plain' # (Use plaintext documentation emitter)
|
||||
bash: curl -X GET http://api.django-rest-framework.org/ # (Use default renderer)
|
||||
bash: curl -X GET http://api.django-rest-framework.org/ -H 'Accept: text/plain' # (Use plaintext documentation renderer)
|
||||
|
||||
The examples provided:
|
||||
|
||||
1. A basic example using the [Resource](http://django-rest-framework.org/library/resource.html) class.
|
||||
2. A basic example using the [ModelResource](http://django-rest-framework.org/library/modelresource.html) class.
|
||||
3. An basic example using Django 1.3's [class based views](http://docs.djangoproject.com/en/dev/topics/class-based-views/) and djangorestframework's [EmitterMixin](http://django-rest-framework.org/library/emitters.html).
|
||||
3. An basic example using Django 1.3's [class based views](http://docs.djangoproject.com/en/dev/topics/class-based-views/) and djangorestframework's [RendererMixin](http://django-rest-framework.org/library/renderers.html).
|
||||
4. A generic object store API.
|
||||
5. A code highlighting API.
|
||||
6. A blog posts and comments API.
|
||||
|
|
Loading…
Reference in New Issue
Block a user