Yet another implementation of class based RESTful dispatch. This particular implementation features:
- You do not have to call init from the derived classes.
- Avoids metaclass which (in our environment) led to unexpected method override behavior.
- Method names match the google webapp API.
- One new instance per request to reduce errors in multi-threaded code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | from django.http import HttpResponse
from django.http import HttpResponseNotAllowed
METHODS = sorted(('get', 'post', 'head', 'options', 'put', 'delete'))
class ResourceView(object):
"""\
@brief Base class which implements restful dispatch on a resource
To use this class you derive from this class and provide an
implementation for any of the methods in the METHODS tuple found
at file scope in this file.
Define a class which extends ResourceView.
class Region(ResourceView):
def get(self, request):
...
def post(self, request):
...
And then in urls.py, dispatch to a new class instance via the call:
urlpatterns = patterns(
'',
(r'^region/$', views.Region.dispatch))
The call to dispatch call will automatically generate a private Region
instance which will live for the lengh of the HTTP request/responce
cycle and then discarded.
The ResourceView class will generate a reasonable default
implementation of head() if your class does not provide one and
defines get().
*NOTE: Any callable without a leading underscore is considered part of
the public API and may be called by the dispatch. Make sure you
prepend underscores in implementation methods which should not be
accepting direct connections from a client.
"""
@classmethod
def dispatch(klass, request, *args, **kwargs):
"""\
@brief classmethod which is the django callable to call during
RESTful dispatch.
@param klass The derived class we are calling.
@param request The Django request object.
@return Returns the response in klass in the matching
request.method.
"""
return klass().__dispatch(request, *args, **kwargs)
def __not_allowed(self):
"""\
@breif Generate the HTTP Not Allowed message for the client.
"""
allow = []
for method in METHODS:
if hasattr(self, method):
allow.append(method)
if 'get' in allow and 'head' not in allow:
allow.append('head')
return HttpResponseNotAllowed(k.upper() for k in allow)
def __default_head(self, request, *args, **kwargs):
"""\
@brief Simple implementation of HEAD.
This is implemented as a private method because we cannot add
automatic support for HEAD unless the instance supports GET
which has to be detected at runtime in this code structure.
"""
response = self.get(request, *args, **kwargs)
if not isinstance(response, HttpResponse):
return ''
response.content = ''
return response
def __no_method(self, request, *args, **kwargs):
"""\
@brief This method is called when the derived class does not
implement the HTTP method invoked on the object.
"""
if request.method == 'HEAD' and hasattr(self, 'get'):
return self.__default_head(request, *args, **kwargs)
return self.__not_allowed()
def __dispatch(self, request, *args, **kwargs):
"""\
@brief Class level implementation for classmethod dispatch.
"""
method = request.method.lower()
if method.startswith('_'):
# do not allow people who make up bad http methods to call
# into the private implementation details. Phoenix 2009-05-21
return self.__not_allowed()
return getattr(self, method, self.__no_method)(request, *args, **kwargs)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.