Version 2 (modified by Ben Firshman, 8 years ago) (diff)


Class-Based Views

The proposal to add a class-based framework for describing views (#6735) has been around for a while. It's been proposed for inclusion in Django 1.0, 1.1, and 1.2. This is a summary of the state of debate, with the intention of landing a patch for the 1.3 release.

The brief

At present, generic views are defined as methods. If you want to customize them, you have to pass in arguments to the view at time of use in This is cumbersome:

  • rapidly becomes large an unwieldly
  • complex behaviors that need to be wrapped in callables depend on the underlying views handling callable arguments (which isn't implemented universally)
  • There's no such thing as a simple extension -- you can't easily say "use that view, but change one argument"; you have to reproduce the full argument list.
  • .. and much more

Moving to a class-based structure means that the complexities of defining and customizing generic views can be handled by subclassing. returns to being a simple process of pointing at a class. Extension logic can be arbitrarily complex, abstracted behind methods on the generic class. It also means we can provide an entry point for HTTP method-based dispatch -- e.g., a GET() method to handle GET requests, POST() to handle posts, etc.

The problem

However, the devil is in the detail. There are several issues that any class-based view solution needs to address:

  • Deployment: How do you deploy an instance of the view
  • URLResolver interaction: Does the approach require any special handling in URLResolver to identify and/or instantiate the view?
  • Subclassing: How easy is it to subclass and override a specific method on a view class?
  • Thread safety: Does each request get a clean instance of self to work with? If so, how is this achieved?
  • Ease of testing: Does testing the view require any special handling (such as a specialized method to instantiate the view)
  • Ease of decoration: Does the proposed technique pose any impediments to easily decorating views?

View instantiation and thread safety

The most recent django-developers discussion on the topic discussed many of the available options on instantiating the views and protecting them from threading issues. Here is a summary of the various approaches that have been proposed.

__call__() and copy()


Example usage:

    url(r'^detail/author/(?P<pk>\d+)/$', views.AuthorDetail(), name="author_detail"),

Example class:

class AuthorView(View):
    def GET(self, request, *args, **kwargs)
        return self.render_to_response('author_list.html', {'authors': Author.objects.all()})

This approach proposes that an class instance be placed in; the instance has a __call__() method, and when that method is invoked, it takes a shallow copy of the instance defined in, and returns the result of invoking the request method (e.g., GET()). This achieves thread safety by ensuring that every request is given a clean instance on the view class to work on.

No special handling is required in UrlResolver -- the class instance is a callable, so it appears just like an existing view function.

Arguments against:

  • The "copy on __call__()" approach is a little messy. Normal Python idiom wouldn't lead users to expect that __call__() would cause a copy to be created. However, this is entirely hidden by the implementation.



Example usage:

    url(r'^detail/author/(?P<pk>\d+)/$', views.AuthorDetail, name="author_detail"),

Example class:

class AuthorView(View):
    def GET(self, request, *args, **kwargs)
        return self.render_to_response('author_list.html', {'authors': Author.objects.all()})

This approach is much the same as the __copy__() on __call__() approach, except that __new__() is used to create the new instance.

Arguments against:

  • You can't use arguments to init() to instantiate a class view
  • x = AuthorView() returns x as a HTTPResponse, not an AuthorView instance. This violates expectations of normal class usage.

HTTPResponse subclassing


This approach exploits the fact that the aim of a view is to produce a HttpResponse instance; so it shortcuts the process, and makes a 'view' the constructor for the HttpResponse.

Arguments against:

  • Binds the Response object the concept of a view. A view isn't 'is-a' response, in the OO-sense.
  • Makes it difficult or impossible to subclass HttpResponse and use that subclass
  • Makes it difficult to use HttpResponse-returning methods; you can't just call out to a subview/utility method that returns a HttpResponse instance, because the view needs to return 'self'.

UrlResolver view instantiation

Rather than try to make the view look like a callable, this approach modifies UrlResolver so that it can identify when a class-based view is in use, and instantiate an instance when one is detected.

Arguments against:

  • Requires special cases in UrlResolver which almost inevitably involve isinstance(ViewClass) or some analog.


Based on these discussions, plus in-person discussions at, __copy__() on __call__() appears to be a slight front runner, with __new__() as a close runner up.

How to help

Class-based views are being developed as a separate application on Github. There are a few things yet to be done:

  • A simple readme for getting started
  • Testing it in real applications
  • More test coverage
  • Support for ModelForms that mimics the current generic views
  • Full documentation

Fork the Github project if you want to help out.

Back to Top