| 96 | |
| 97 | === Class Hierarchy === |
| 98 | |
| 99 | There are several ways to lay out the tree of classes that will make up both the base views and the new generic views. |
| 100 | |
| 101 | The 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. |
| 102 | |
| 103 | === Method-based dispatch === |
| 104 | |
| 105 | This 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. |
| 106 | |
| 107 | The 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. |
| 108 | |
| 109 | === Storing request, args, kwargs on self === |
| 110 | |
| 111 | One 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. |
| 112 | |
| 113 | Advantages: |
| 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 |
| 116 | |
| 117 | Disadvantages: |
| 118 | - Won't work if there's not one instance per request |
| 119 | |
| 120 | The 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. |
| 121 | |
| 122 | === Methods for everything === |
| 123 | |
| 124 | Some 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). |
| 125 | |
| 126 | For 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). |
| 127 | |
| 128 | === Justification === |
| 129 | |
| 130 | There are quite a few sets of class-based views out there already; they include: |
| 131 | |
| 132 | - Andrew Godwin's baseviews (https://bitbucket.org/andrewgodwin/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 (http://github.com/bkonkle/django-baseviews) |