HowTo: Django view as a class

2 views
Skip to first unread message

zvoase

unread,
Aug 25, 2008, 9:07:14 PM8/25/08
to Django users
Hey Django users, just a quick suggestion which might help a few
people.
I have come up with 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.

I've written a general class, Resource, which 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 sample resource may look like this:

# CODE START #

class Book(Resource):
def get(self, request, book_name):
book = myapp.models.Book.objects.get(name=book_name)
return render_to_response('book_template.html', {'book':
book})

def put(self, request, book_name):
new_book, created = get_or_create(myapp.models.Book,
name=book_name)
new_book.data = request.raw_post_data
if created:
return HttpResponse(status=201)
return HttpResponse(status=200)

def delete(self, request, book_name):
book = myapp.models.Book.objects.get(name=book_name)
book.delete()
return HttpResponse()

# CODE END #

You can see how these methods correspond to GET, PUT and DELETE
request methods, and the dispatch is performed in the __init__ method
defined in the Resource class. HttpResponse instances can be returned
from these methods, and their data will be merged with 'self' by
__init__.

Okay, so here's the code I've written:

# CODE START #

class Resource(HttpResponse):
def __init__(self, request, *args, **kwargs):
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)

def update(self, response):
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

def render_to_response(self, *args, **kwargs):
self.update(render_to_response(*args, **kwargs))

# CODE END #

I hope people find this useful.

Regards,
Zack

V

unread,
Aug 26, 2008, 10:00:54 AM8/26/08
to Django users
Hi!

Interesting solution.

Another possibility if you would like to stick with a class is to
simply define a __call__ method on the class. Of course, this doesn't
have to do anything with RESTfulness.

V

Jenan Wise

unread,
Aug 27, 2008, 2:51:38 PM8/27/08
to django...@googlegroups.com
V: Defining a __call__ method will make *instances* of the class callable.  Calling the class itself will still just instantiate it.

zvoase

unread,
Aug 28, 2008, 12:50:10 PM8/28/08
to Django users
An alternative is to use some metaclass programming, but to be honest
it's more trouble than it's worth. This does actually help with
RESTfulness, because it allows you to aggregate your views on a
resource-centric basis, as a collection of atomic operations on a
resource, and then you would define a mapping between URLs (Uniform
RESOURCE Locators) and Resource subclasses. So yes, it does help with
RESTfulness.

Regards,
Zack

On Aug 27, 8:51 pm, "Jenan Wise" <jenanw...@gmail.com> wrote:
> V: Defining a __call__ method will make *instances* of the class callable.
> Calling the class itself will still just instantiate it.
>

bobhaugen

unread,
Aug 28, 2008, 5:36:11 PM8/28/08
to Django users
I would be interested to try this in the context of a whole simple
app, if you ever publish such a thing.

Horst Gutmann

unread,
Aug 29, 2008, 3:26:43 AM8/29/08
to django...@googlegroups.com
Very interesting approach, going through subclassing HttpResponse for
generating views. Just some more alternatives if you don't mind ;-)

A couple of months ago, Arne Brodowski wrote some similar on his blog
[1] also kind of using the servlet-split (a view-method per
http-method). Also some time ago I simply took the __call__-approach
combined with a small view-factory [2].

[1] http://www.arnebrodowski.de/blog/488-Eine-andere-Moeglichkeit-GET-und-POST-in-Django-zu-verarbeiten.html
[2] http://github.com/zerok/django-zsutils/tree/master/utils/oopviews.py

-- Horst

Reply all
Reply to author
Forward
0 new messages