baseviews /

Filename Size Date modified Message
2.6 KB

This is my first pass at writing a set of generic class-based views for Django.

It's not perfect - it was written in a few days in a remote part of the Scottish Borders -
but it's a start, and has been changed and modified as we used it to build a real project.

There are several design decisions that could really go either way, and I have no doubt
there's good arguments for either side. Here are my decisions, and their justifications.

 - A set of small, mixed-in and inherited base classes rather than one big monolithic
   class. Ben Firshman's original code that I based this off had one massive class with
   every possible eventuality covered (different return formats, templates, etc.)
   I decided to go for a set of inheriting classes and mixins that provide these features;
   it feels more Pythonic to me, and also means you don't have extra methods kicking
   around that you don't need.

 - Views have to be instantiated in the urlconf. This allows you to pass in keyword
   arguments to override things like template names, if you want. There's a check
   in the constructor which makes sure a sensible error is raised if you forget to
   instantiate them. Whenever a class is called to render to a response, it
   uses copy() on itself to ensure you can store things on self while being threadsafe.

 - Method dispatch is in the basemost class, as part of __call__. This seems like
   something that nearly every class-based view will want to be distinguishing on,
   and if not, doing POST = GET in the class body is still quite nice.

 - request, args, and kwargs are stored on self. This was a tough decision, and the
   package started with request, args and kwargs being passed around in all the
   function calls, but this either clutters the method signatures or restricts the
   flexibility of subclasses, depending on how many functions you insist on passing
   this into. In the end, having them on the object itself is both threadsafe (since
   it's copied on call) and provides for much nicer calls around the class (like
   self.get_object() rather than self.get_object(request, *args, **kwargs) everywhere)

 - The default functions - like render() - don't call other subfunctions to get context,
   etc. Most things - like form_valid, or just GET on most classes - do call other methods
   for important parts, but are also simple enough that you can override them completely
   and add a few more lines. We found having tens of small functions for everything made
   subclasses' logic much more unreadable than just writing a new form_valid or a new GET.