by Nick Lang -- Sept. 17, 2011, 1:48 p.m.
So since Django 1.3 came out the new hotness has been Class Based Views. I remember taking a look at the documentation and thinking to myself this is fine and all, but I still don't quite understand what's going on. If you're like me I hope I can take my expereiences and translate them into something that's a little more helpful and you too can get up and running with CBV's.
What we are going to do is actually go through what it takes to convert a classic view to a CBV subclassed from django.views.generic.base.View. I think this will give the best starting point for understanding how a CBV actually works.
First lets look at a very simple, classic view:
from django.shortcuts import render_to_response
from django.template import RequestContext
from awesome_project.awesome_app.models import MyModel
def awesome_view(request, *args, **kwargs):
template = kwargs.pop('template', "mytemplate.html")
object_list = MyModel.objects.filter(**kwargs)
return render_to_response(template,{
'object_list': object_list,
}, RequestContext(request))
This is a very simple view, that just grabs a queryset from the database and returns it as a context variable object_list.
As we all know to execute this view we need to have our url_conf set up something like this:
from awesome_project.awesome_app.views import awesome_view
urlpatterns = patterns('',
url(r'^awesome$', awesome_view, {}, 'my_awesome_view'),
)
Now to translate this to a CBV lets look at the base View object at django.views.generic.base.View, and see how we can turn our simple classic view into a simple generic CBV.
This CBV lets us implement the same functionality that our classic view did:
from django.views.generic.base import View
from django.shortcuts import render_to_response
from django.template import RequestContext
from awesome_project.awesome_app.models import MyModel
class AwesomeView(View):
template = "mytemplate.html"
def dispatch(self, request, *args, **kwargs):
object_list = MyModel.objects.filter(**kwargs)
return render_to_response(self.template,{
'object_list': object_list,
}, RequestContext(request))
So now in this example our CBV AwsomeView is doing the exact same thing as our previous example (the classic view).
In order for our urls to reflect this CBV we need to make a small change:
from awesome_project.awesome_app.views import AwesomeView
urlpatterns = patterns('',
url(r'awesome$', AwesomeView.as_view(), {}, 'my_awesome_view'),
)
What's going on in this CBV? Well all generic CBV's in Django subclass View, like we did here. The importat distinction is what we've done in this example is we just overrode the dispach method. The dispach method comes in all generic views and it's sole purpose is to:
Try to dispatch to the right method; if a method doesn't exist, defer to the error handler. Also defer to the error handler if the request method isn't on the approved list.
What this means is dispatch will look at your request method and try to find out how to process the request. More clearly, is the request.method a POST or a GET etc..
Note the http methods that dispatch is looking for are:
get,post,put,delete,head,options, andtrace.
Now that we know what the dispatch method is supposed to do, lets not override it. Now it can work as originally intended:
from django.views.generic.base import View
class AwesomeView(View):
template = "mytemplate.html"
I'm sure you're thinking to yourself, "Now what?" Good question. Well since the dispatch method is used to dispatch the view to the right handler, we actually need to create the handler method like so:
from django.views.generic.base import View
from django.shortcuts import render_to_response
from django.template import RequestContext
from awesome_project.awesome_app.views import AwesomeView
class AwesomeView(View):
template = "mytemplate.html"
def get(self, request, *args, **kwargs):
object_list = MyModel.objects.filter(**kwargs)
return render_to_response(self.template,{
'object_list': object_list,
}, RequestContext(request))
Great. Now our view works just like before. Only this time we are letting the distpach method do the work for us to divy out the request to specific methods for handleing specify types of requests. In this example, we are letting dispatch call the get method for handling the request.
Now that we understand how django's class based views work, Part 2 will start looking at some of the other generic views and how we can use these in real life.