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.

Reply via email to