Resource

The Resource class is a way of writing a Django view as a class. I've done this as part of an effort to write easier-to-understand RESTful apps, as this allows the grouping of similar views as different types of operation on a resource. Essentially, the solution goes something like this:

Views have to be callables which return HttpResponse objects.

The problem with views as classes is that calling a view class returns an instance of the view class, not HttpResponse.

Solution: have the VC (view class) a subclass of HttpResponse. This way, 'calling' the class will return a HttpResponse instance.

The Resource class performs a dispatch on the request method, so that a resource can be retrieved, created/updated and deleted by writing 'get', 'put' and 'delete' methods on a subclass of Resource.

A general Book class shows how this might work for the case of 'books' in a system:

importstringfromdjango.httpimportHttpResponse,HttpResponseNotAllowedclassResource(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)ifhasattr(self,request.method.lower()):value=getattr(self,request.method.lower())(request,*args,**kwargs)ifisinstance(value,HttpResponse):self._update(value)elifhasattr(self,'run'):value=self.run(request,*args,**kwargs)ifisinstance(value,HttpResponse):self._update(value)else:allowed_methods=[]forattrindir(self):ifset(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._charsetself._is_string=response._is_stringself._container=response._containerself._headers.update(response._headers)self.cookies.update(response.cookies)self.status_code=response.status_code