4

For creating a large Django project with many apps, my first initial thought was to used Class Based Views (as the Django tutorials seem to emphasize). However, I noticed that due to a lot of the customizations to each app (multiple forms on each page etc), it became very tedious and was much easier to just implement Function Based Views where I just added decorators such as @require_GET and @login_required for easy authentication and method not supported messages, and am thoroughly convinced I will never go back to CBVs.

From a long term support perspective, has anyone had issues with choosing FBVs over CBVs? Am I doing something in the short term that will hurt long term, and could perhaps be solved by custom Class Based Views?

Update 12/2014

I have now become a complete advocate for CBVs! I will never go back! The reusability, inheritance, mixings create for an absolutely reusable and flexible system. I have reduced the amount of code I've used by a huge percent thanks to CBVs. There was admittedly a learning curve and I did not immediately see the results, but after refactoring I could not be happier. For large projects, it seems that CBVs are a necessity.

4

On a number of occasions, I've had to drop down into code from a package. Some of them are FBV, some are CBV. I always have a harder time with the class based views. I just find it harder to follow. Particularly inheritance can be annoying to debug.

My own code is function based. I just find it very simple to find what I'm after. After all, most of the debugs start with a url. You just look in the url file, and that tells you what to look for in the views file. The view is pretty easy to follow, even if it has a lot of boilerplate (if POST etc...). But basically it's all right there in one place.

Class based views make it unobvious what is being executed. When something is inheriting from something else, the flow goes back and forth between the parent and the child. This isn't great for debugging.

3

CBVs tend to make a lot of things easier once you get the hang of them. While it may seem like everything is extremely complicated if you just subclass TemplateView for everything, CBVs take a lot of unnecessary boilerplate away when you really need to have them.

CBVs also help organize things into bite-size pieces. The name of the template used for your view will pretty much always be the template_name variable. What happens when my function gets a GET request? It calls get(). POST? That's post(). Instead of having multiple codepaths, you now have two mutually exclusive functions that each independently handle a different scenario. What's in my context? Check out get_context_data. Need to display info about a DB object? Make a DetailView, with the PK in the URL and the model defined in the view. No manually coding DB lookups (though you can specialize the queryset if you want it). If you're dealing with a form, it will run all the validation for you, and then you just need to define form_valid (runs when the form is valid), and probably don't even need to bother with form_invalid, since the default is just to recall the page with the errors in the form.

The key to using CBVs effectively is to know which CBV to use for the right scenario. Writing up a FBV to display an object creation form, validate it, and create the object is a pain in the butt, but a CreateView CBV just requires the form class, model class, and template name. DetailView is great for just spitting out info from a database. If you're doing something like a blog where year/month/day lookup would be useful, there's a half a dozen different date-based CBVs that will automate most of it.

Most notably, FBVs give you no choice other than to create a monolithic function, and while extremely simple views might be faster and easier in FBVs, the fact that CBVs encapsulate each step of the rendering process (dispatching, retrieving templates, handling different request types, passing context variables, validating forms, etc) makes anything even remotely complex much easier to break down. You also generally don't need to declare most CBV functions, since the defaults are pretty sane. If you let the CBVs do most of the work for you, you'll end up with a much better appreciation for them.

A couple tips that I've found extremely helpful:

  • https://github.com/brack3t/django-braces - Braces is a CBV mixin library, which provides a lot of helpful mixins for CBVs. Instead of using an FBV and decorating with @login_required, you can make your view a subclass of LoginRequiredMixin and it'll do the same thing. It also has mixins for superuser access, permission based access, and even JSON access for APIs and AJAX calls.
  • If you're absolutely attached to your decorators, note that you can still use FBV decorators for CBVs by decorating the dispatch function in your CBV. As a result, the following is equivalent:

    @login_required
    def FunkyView(request):
        return HttpResponse("Funky!")
    
    class ClassyView(View):
        @login_required
        def dispatch(self, request, *args, **kwargs):
            super(ClassyView, self).dispatch(request, *args, **kwargs)
    

    You can also decorate the as_view function in the URLConf, like so:

    url(r'^classy/$', login_required(ClassyView.as_view()), name='decorated_classy')
    
  • http://ccbv.co.uk/ is the ultimate resource for Class Based Views, giving you an easy way to view CBV code, see what inherits from what, and see where functions are available.

  • For the record, I have completely adopted CBVs and couldn't be happier. – C.B. Dec 12 '14 at 22:15
  • 2
    In that case, you should change your accepted answer. Glad to hear things are working well for you! – Seven Deadly Sins Dec 14 '14 at 0:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.