On Oct 2, 10:32 pm, Russell Keith-Magee <russ...@keith-magee.com> wrote:
> I completely agree that we don't want to rush this. The upside is that > if we *can* reach consensus, it isn't going to require a whole lot of > code changes; We're arguing about how to architect the base class, but > once we've got that sorted out, Ben's patch is feature complete and > shouldn't be too hard to adapt to any base class along the lines of > what we've been describing. Given that most of this thread has been dedicated to simply discussing "how to architect the base class", I think that there is an opportunity to discuss other elements of the implementation that have been neglected up to now. While bfirsh's implementation may be *almost* feature complete, it seems to be lacking one major feature that will be important to many, if not most, users; specifically, the ability to easily return data *other than* html rendered from a template. A large number of users, if not a majority, will want to be able to use class-based views to return JSON data. Others will want to render and return XML or PDF data. Some users may even want to use django-annoying's @render_to and @ajax_request decorators, and would have classy views return dictionaries instead of HTTPResponse objects. Of course, users could subclass the base View class to do any of these things, but then they would be discarding most of this module's useful functionality. The real power of class-based generic views will be found in the subclasses included in the module (ListView, DetailView, etc.). The real power will be the ability to re-use the generic list- processing, detail-processing, and form-processing code, not in the high-level architecture of the base class. Users, I think, should be shown an obvious and intuitive path by which they may reuse the data-processing logic of these generic view objects without being limited to a single output format, and without having to jump through hoops in terms of subclassing disparate objects and overriding tricky methods that differ from subclass to subclass in terms of both signature and implementation. At this moment in time, TemplateView is a base class of all of View's descendant classes in bfirsh's implementation. All inheritance flows through TemplateView for the entire library. Furthermore, every data- processing subclass of View references TemplateView's render_to_response method, which is oriented in its implementation and (more importantly) its signature only towards template processing. As a result, any user wanting to implement a JsonView, an XMLView, or a PDFView will need to subclass a subclass of TemplateView in order to reuse the generic views' data-processing code, and will also have to know quite a bit about the intricacies of how the different methods interact inside each of these classes. This sub-optimal for a number of reasons: 1. Views that neither render html nor use templates will report that they are TemplateView instances (via isinstance()). 2. In order to create a suite of generic JsonViews, for example, many different classes will have to be subclassed, and the methods that are overridden will not be consistent across those subclasses. 3. It is unlikely that any of this will be documented, and the overriding rules will not be intuitive nor obvious, leading to confusion and support requests. A moderate refactoring of the internals of the implementation, along with a willingness to see some of the lower-level implementation details of the generic view objects as part of the public API, could resolve these issues. My own suggestion is as follows: * First, treat data processing and retrieval as separable from rendering. Create a bright line of separation between the two conceptual elements of the view (data and rendering), and do it early on, at a high level, inside dispatch(). Instead of expecting the ListView.GET to return an HTTPResponse, for example, have it return a context or a context dictionary that could be reused with several render_result() implementations. * Second, have the dispatch method in View call render_result(context_dict), which will raise a NotImplemented exception in the base class, but will return in the subclass whatever the return data might be. This will be the locus of control for different data implementations, and can largely be implemented without any knowledge of the data processing details. * Third, provide different implementations of render_result() through the use of different mixins, each targeting a different output style (template, json, XML, PDF, etc.). That way, the logic that handles data processing and retrieval can be re-used regardless of what the data output may be, and vice-versa. * Finally, handle redirects, reloads, or 404's through exceptions, which would be processed inside dispatch() as well. Using exceptions for normal flow of control is generally frowned upon, but here it would allow for a simplified API description for calls to GET(), POST(), etc.: These methods would return a dictionary in the standard case, and raise specialized exceptions for redirects, reloads, or file- not-founds and other deviations from the "norm." The current implementation is already using mixins in order to maximize code reuse in form processing. It seems that using mixins to modify rendering behavior would also be appropriate. And if mixins are unacceptable for the documented API ("mixins are a relatively unused part of Python, and multiple inheritance can cause some odd bugs"), the same compartmentalization can be achieved, albeit in a more repetitive way (copy and paste), by simply overriding render_result(context_dict) in direct subclasses of ListView, DetailView, etc. Most significantly, however, it would be much easier to document how a user can add his or her own response data type if such a thing were limited to nothing more than overriding render_result(context_dict). Of course this is just one example of an approach. There are other approaches that would also be an improvement over what is implemented. If I have a more over-arching point here it is this: the API for the base class may be the most important issue to decide before committing to include this feature in version 1.3, but it is certainly not the only one. Rather than assuming that all other issues are settled, I think it might be more correct to see the architecture discussion as having preempted the other conversations that need to take place. For what it's worth, I would personally love to see this feature in version 1.3, but it seems more important that it be done right, and I am sure that everyone participating in this discussion would agree. The lower-level aspects of the implementation need to be more thoroughly vetted before this feature should be considered suitable for inclusion, IMHO. Regards, Eduardo Gutierrez -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.