Do I use function-based views, class-based views or generic CBVs?
It’s no big deal.
Right now, there’s three major (built-in) ways to write a view in Django. Either you:
- write a simple function
- write a class which inherits from the View class or
- choose one of the dozen-or-so generic class-based views to extend
It can feel like a huge decision – you don’t know if the decision will bite you eventually, or if you’re missing out on something really cool.
But it’s not.
Simple is better than complex
The third line in the Zen of Python is a good guiding rule, and applies in this case.
Especially when you’re starting out, you don’t need to find solutions to problems you don’t have.
For simple views and apps, you can make a great deal of progress before you run into the reasons why class-based views were introduced. When you feel like you’re repeating yourself too often, is a good time to look into CBVs and mixins. Until then, you can get the same functionality with any of the methods.
If you’re comfortable with function-based views, you can continue using them. If you started out with class-based views you can go a long way, just inheriting from the View class.
Be wary of trying to customized generic CBVs without learning about them in-depth. Usually, it’s just easier to write your own non-generic view, than trying to use them unprepared.
I prefer the class-based views which are based on the View class, unless the project is large enough that there’s a lot of repetition going on. Then you can refactor to be more on the DRY side of things.
A Simple Comparison
Reading code helps to get a feel for this topic, and move on. Let’s look at how rendering a template would look with all three methods.
We’re going to write a class-based view, which inherits from the View class, use a generic TemplateView with a bit of custom context data to pass to the template and a function-based view:
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView
class TestViewCBV(View):
def get(self, request):
template_name = 'test.html'
# this data dict will be added to the template context
data = {}
data["message"] = "Hi!"
return render(request, template_name, data)
def post(self, request):
# we don't handle POST requests
pass
class TestViewGeneric(TemplateView):
template_name = "test.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['message'] = "Hi!"
# this data dict will be added to the template context
return context
def test_view(request):
if request.method == 'GET':
template_name = 'test.html'
# this data dict will be added to the template context
data = {}
data["message"] = "Hi!"
return render(request, template_name, data)
else:
# we don't handle POST requests
pass
All of them do the same thing - render a template upon receiving a GET request. The class-based view and function-based view simply ignore POST requests.
If you want to add more functionality - I’d stick to the class-based view or the function-based view, and ditch the generic TemplateView when starting out, instead of trying to customize it.
Either way, you’re fine using FBVs or CBVs - just don’t try to get too fancy with GCBVs in the beginning, and you’ll be fine :)