import string
from django.http import HttpResponse, HttpResponseNotAllowed
class Resource(HttpResponse):
"""Represents a single resource within a RESTful web service.
The ``Resource`` class should be used to represent a single resource
within a RESTful web service. It exists to be subclassed for each
resource within the service, and these subclasses should define a method
for each possible HTTP request method on the so"""
def __init__(self, request, *args, **kwargs):
"""Instantiate a ``Resource`` instance.
This method overrides ``HttpResponse.__init__``, providing an
alternative way of serving views. It calls the overridden method
first, to handle the initialization, and then performs a dispatch
on the HTTP request method. The return values of these methods are
then merged back into the current ``HttpResponse`` instance.
Because this is called like a view function, this method accepts
a request object and any other positional and/or keyword arguments,
These will be passed to the methods defined on a subclass, so those
methods should support any arguments given.
If the given HTTP request method is not defined for a subclass, then
a 405 'Method Not Allowed' response is returned, along with a list
of allowed methods (obtained via introspection)."""
HttpResponse.__init__(self)
if hasattr(self, request.method.lower()):
value = getattr(self, request.method.lower())(request,
*args, **kwargs)
if isinstance(value, HttpResponse):
self._update(value)
elif hasattr(self, 'run'):
value = self.run(request, *args, **kwargs)
if isinstance(value, HttpResponse):
self._update(value)
else:
allowed_methods = []
for attr in dir(self):
if set(attr).issubset(set(string.lowercase)):
allowed_methods.append(attr.upper())
self._update(HttpResponseNotAllowed(sorted(allowed_methods)))
def _update(self, response):
"""Merge the info from another response with this instance.
This method simply copies the attributes from the given response to
this instance, with the exceptions of the ``_headers`` and ``cookies``
dictionaries, whose ``update`` methods are called. This means that any
headers or cookies which are present in this response but not the
argument are preserved."""
self._charset = response._charset
self._is_string = response._is_string
self._container = response._container
self._headers.update(response._headers)
self.cookies.update(response.cookies)
self.status_code = response.status_code
Comments
Interesting approach. My solution to "the problem with views as classes is that calling a view class returns an instance of the view class, not HttpResponse" is to add a call(self, request) method to the class, then use an instance of that class in the URLconf rather than the class itself - see http://www.djangosnippets.org/snippets/1071/ for an example
#
Shouldn't you be checking that attr is in a list of allowed HTTP methods (GET/POST/PUT etc)? Otherwise the client-side could execute arbitrary methods of any subclass of Resource.
#