Thursday, August 30, 2012

Re: Combinable generic CBVs

On Aug 29, 5:24 pm, Melvyn Sopacua <m.r.sopa...@gmail.com> wrote:
> On 29-8-2012 18:46, Rainy wrote:
>
> > On Aug 29, 3:10 am, Melvyn Sopacua <m.r.sopa...@gmail.com> wrote:
> >> On 29-8-2012 4:44, Rainy wrote:
>
> >>> When I use CBVs, I nearly always end up needing to mix different types in
> >>> the same view, e.g. detail view and list view, list view and modelform
> >>> view, etc. I really like CBVs but I feel this is the one shortcoming that I
> >>> constantly run into that makes CBVs much less flexible and helpful than
> >>> they could be.
>
> >> What are your real world cases for this? If you combine several models
> >> to make up a page, you should consider writing your own mixins that
> >> inherit only from ContextMixin and implement get_context_data() to add
> >> the extra information.
>
> <snip example>
>
> > I will give some examples at the end of the message, but first I want
> >  to expand a bit on this idea.
>
> > Let's say you have a detail CBV, FooView(DetailView): model = Foo ;
> >  and a list view, BarView(ListView): model = Bar .
>
> > Now, combining different types of views is an extremely common case
> > and you might say that the cases when you don't need to do that are
> > usually so simple that existing GCBVs already handle them perfectly.
>
> The list and detail view don't bite each other in many aspects. However,
> as you will list in examples below, you usually don't have just one list
> view per page. See below.


Actually, I've never had more than one list per view, either in these
examples or in any other I've worked with. In fact, I've never had
a view where more than one instance of any type of CBV was
needed, as far as I can remember. The only common case I
can think of is having two forms - let's say a search and login.
I think it should be handled as a special case, maybe allowing
form_model to be a list and updating all CBVs to process it
as either a single item or as a list.

>
> > I don't see any apparent reason why the two examples above can't
> > be combined exactly in the same way you inherit each separate view:
> > FooBarView(DetailView, ListView): detail_model=Foo; list_model=Bar.
>
> Because how would you declare a second list model? And how would you
> pick these up? Aside from making the routing through the model
> difficult, this will also be a declaration nightmare.


I showed examples below, doesn't seem like a nightmare, I think..

>
> > As a bonus, you don't have to decide which mixin to use and when
> > overriding methods, you will know which instance variable and method
> > handles detail and list objects.
>
> Except when you need more than one list or detail or both.
>
> > Here are a few examples where it would be useful, and I can find many
> > more in my projects:
>
> >   - blog post: 3 CBVs: post, list of comments, comment form
> >  - search: FormView, ListView
> >  - photo album: detail view for album, listview of images
>
> > I know each of these cases can be handled with current GCBVs but
> > with a lot more effort and in a more verbose and error-prone way
> > than what I'm proposing.
>
> I don't see that:
> class BlogView(CommentListMixin, CommentFormMixin, DetailView) :
>         model = BlogPosts
>
> versus:
> class BlogView(DetailView, ListView, CreateView) :
>         detail_model = BlogPost
>         list_model = Comments
>         form_model = Comments
>
> I find the second version harder to read, more verbose to type and when
> you want to support multiple models you will have to support some sort
> of sequence or mapping.


It's ok that it's more verbose, in fact it's a good thing becase here
verbosity is moved from method level to class attribute level,
I want my methods to be as short and clear as possible, to make
it easier to follow the logic.

> Not to mention how you'd handle template-coder
> friendly names through context_object_name and similar.


Of course, this would be done with declarations like
context_detail_object_name, etc, only for objects
that need to be accessed in template. In this case,
context_create_object_name is probably not needed
and can be left as None.
>
> Yes, the first version requires more work to code the mixins, but I
> don't find them harder to debug either. In fact, pretty much only one
> point where things can go wrong: get_context_data().

No, the issue is the clash between self.object, context_object_name,
self.model. You have to look through the entire tree of CBVs and
make sure all of them refer to the correct objects everywhere
they're referenced. For example, self.object is created in both
get() and post(), if you want to change the default, you have to
override both of them.

The only reason you would use self.object for both detail
and modelform, imho, is to make GCBVs code shorter and
clearer, inheriting from SingleObjectMixin and reusing all
of its code. As a user of GCBVs, it really doesn't matter
much to me if they're a little longer. What does matter to
me is that as soon as I want to combine different types
of CBVs, it's a major pain even though there is no inherent
reason why it needs to be so.
>
> I can see your point and some of my issues with it may well be personal
> preference, but I'm not sure if the Generic CBV's are a good base for
> what you ask of them. I'm currently working on a RelatedModelMixin and


Is related model the case where one is a detail model and the other a
list model? I think that's what you'd run into in 95% of cases, and
it's
made much easier with my proposal.

> subsequently a FormsetMixin and I already feel like I'm coloring outside
> the lines.

> It's made me consider the fact that function based views are more
> natural.


I couldn't disagree more. Whatever the argument may be about current
GCBVs, a flat CBV inherited from View is always 100 times better than
the equivalent FBV. Even the argument about logic flow does not apply
-
you can arrange methods in the order of logic flow if you prefer.

Even though GCBVs weren't a very good design (I've often heard that
the biggest issue is documentation, but I suspect that's what made it
hard to write the docs - if the design isn't very good, how do you
explain
or excuse it in the docs? Why are simple things often so hard and
complex
to implement?); the basic implementation of CBVs is by far the best
thing
that ever happened to Django.


A view really is a process where you hand it some info and it
> returns what you asked for. It's less natural to think of it as a
> collection of parts (objects) in a machine that work together to produce
> your result.
>
> However, once you know the order in which things are flowing through the
> magic machine, debugging them isn't hard and things make a lot of sense
> so I think part of the blame here is in the documentation which is in
> fact improving a lot.
>
> Last but not least, I think you should start writing if you feel
> confident it can be done and is an improvement. It's the best way to
> find out if your ideas can work or if another approach should be sought.


That's what I thought, too, but I was wondering if I'm missing some
obvious problems with my approach.

Thanks for the feedback.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.

No comments:

Post a Comment