Changes between Version 2 and Version 3 of ClassBasedViews

10/01/2010 10:17:35 AM (8 years ago)
Andrew Godwin

Adding a few more "bikeshed-worthy" topics, and a reasonable first recommendation for each.


  • ClassBasedViews

    v2 v3  
    2828The [ 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.
    30 === !__call!__() and copy() ===
     30==== !__call!__() and copy() ====
    3232[ Implementation]
    5151 * 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.
    53 === !__new!__() ===
     53==== !__new!__() ====
    5555[ Implementation]
    7373 * x = !AuthorView() returns x as a HTTPResponse, not an !AuthorView instance. This violates expectations of normal class usage.
    75 === HTTPResponse subclassing ===
     75==== HTTPResponse subclassing ====
    7777[ Implementation]
    8484 * 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'.
    86 === !UrlResolver view instantiation ===
     86==== !UrlResolver view instantiation ====
    8888Rather 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.
    9191 * Requires special cases in !UrlResolver which almost inevitably involve isinstance(!ViewClass) or some analog.
    93 === Recommendation ===
     93==== Recommendation ====
    9595Based 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.
     97=== Class Hierarchy ===
     99There are several ways to lay out the tree of classes that will make up both the base views and the new generic views.
     101The current recommended approach is to use mixins to achieve certain parts of functionality (e.g. "rendering a form", "accepting form arguments", etc.), then combine these into generic views. While mixins are a relatively unused part of Python, and multiple inheritance can cause some odd bugs, the idea is to have the fact mixins are used as more of an implementation detail rather than part of the public API.
     103=== Method-based dispatch ===
     105This involves having the base view automatically call self.GET for GET requests, self.POST for POST requests, and so forth. This has the advantage of saving boilerplate for several types of view, but the disadvantage of getting in the way if you do want to share a lot of code between GET and POST methods.
     107The recommended solution is that the very base view have only a dispatch() method (or a similar name) that gets called per-request, and then a subclass that also ships with Django that does method-based dispatch, which would probably be used by a lot of the class-based generic views.
     109=== Storing request, args, kwargs on self ===
     111One more controversial move is, if we have one instance per request (which is looking more likely), whether the request object and any positional/keyword arguments from the URL should be only passed around in the actual function calls, or stored on self.
     114 - Allows much less fragile code (functions are far less subclassable if it's been decided in advance they will never see the request object)
     115 - Cleaner method signatures
     118 - Won't work if there's not one instance per request
     120The current recommendation is that, if one instance per request is chosen, that these are stored on the instance of the view (using the names `request`, `args` and `kwargs`), and that the `dispatch()` and `GET()`, `POST()`, etc. methods still take these as parameters, but all other methods (like `render()`, or `get_form()`) don't.
     122=== Methods for everything ===
     124Some attempts contain methods for everything - one to get the context instance, one to get the context data, one to get the whole context object, and so on. In real-life usage, this turns out to be both very verbose to override as well as being mostly unused (if I want to override how things are rendered, it's a lot easier to just provide a new `render()` function than to override five different other methods, and the logic flow can be changed as well).
     126For this reason, the current recommendation is to break things down into moderately-sized chunks, but not too small - 5 lines or more. Things like template names/patterns should probably be provided as overrideable attributes on the class, however (just not which context instance one should use).
     128=== Justification ===
     130There are quite a few sets of class-based views out there already; they include:
     132 - Andrew Godwin's baseviews (, which was developed alongside a project being built, and has some information about why certain patterns were chosen in the README.
     133 - bkondle's django-baseviews (
    97135== How to help ==
Back to Top