class based views: object instead of dictionary as context?

289 views
Skip to first unread message

Reinout van Rees

unread,
Sep 1, 2011, 4:46:58 PM9/1/11
to django-d...@googlegroups.com
Hi,

I've got one big what's-the-design-decision/reason question regarding
django 1.3's new class based views: why does django encourage a
hand-crafted context dictionary instead of "just" passing the view
object along?

In zope/plone, I was used to having the view object available in the
template as 'view'. The django equivalent would be to pass a context of
{'view': self} to the template.

All the attributes on the view class (well, object) would be available.
Django prefers the template to stay simple and stupid: what could be
better than encouraging to just add extra methods to the class if you
want something special? Now you have to add the method *and* pass it
along in the dictionary. Double work?

Passing the view object to the template by default seems to me to be an
absolute no-brainer. Class based views ought to mean you get the view
object in your template, right? But Django doesn't do it. So... is there
a specific reason for it?

Reinout

--
Reinout van Rees http://reinout.vanrees.org/
rei...@vanrees.org http://www.nelen-schuurmans.nl/
"If you're not sure what to do, make something. -- Paul Graham"

daonb

unread,
Sep 2, 2011, 1:25:08 AM9/2/11
to Django developers
Hi Reinout,

IMHO, Django's philosophy is that template designers are highly
skilled designers and not coders. To make it possible for designers
to edit the templates themselves, Django requires the developer to
create a simple context dictionary for designers to understand.

In all of my projects so far I didn't have the luxury of a designer
who'se fluent in Django templates and can write them by himself, but
still, I like Django for showing a clear way for designers and coders
to work together.

Benny
> rein...@vanrees.org            http://www.nelen-schuurmans.nl/

Greg Donald

unread,
Sep 2, 2011, 3:00:12 AM9/2/11
to django-d...@googlegroups.com
On Thu, Sep 1, 2011 at 3:46 PM, Reinout van Rees <rei...@vanrees.org> wrote:
> why does django encourage a hand-crafted
> context dictionary instead of "just" passing the view object along?

I think it's the worst part of using Django. Having to manage a
context dictionary in every view is weak.

> Now you have to add the method *and* pass it along in the
> dictionary. Double work?

It is double the work, no doubt about it. Not to mention on
complicated views the context dictionary gets quite long. At that
point I usually just package everything up as a single entry.


--
Greg Donald

Greg Donald

unread,
Sep 2, 2011, 3:01:23 AM9/2/11
to django-d...@googlegroups.com
On Fri, Sep 2, 2011 at 12:25 AM, daonb <benn...@gmail.com> wrote:
> IMHO, Django's philosophy is that template designers are highly
> skilled designers and not coders.  To make it possible for designers
> to edit the templates themselves,

Planning for designers to work in code is an extreme edge case. In 15
years of web development I've never once worked with a single designer
who was interested in touching any code. As far as my own web
projects go, the designer is done the moment they give me a layered
.psd.

> Django requires the developer to
> create a simple context dictionary for designers to understand.

How is something like {{ view.myvar }} any harder than {{ myvar }} for
those two designers in the whole world who actually want to touch the
code?


--
Greg Donald

Russell Keith-Magee

unread,
Sep 2, 2011, 3:55:52 AM9/2/11
to django-d...@googlegroups.com
On Fri, Sep 2, 2011 at 1:25 PM, daonb <benn...@gmail.com> wrote:
> Hi Reinout,
>
> IMHO, Django's philosophy is that template designers are highly
> skilled designers and not coders.  To make it possible for designers
> to edit the templates themselves, Django requires the developer to
> create a simple context dictionary for designers to understand.
>
> In all of my projects so far I didn't have the luxury of a designer
> who'se fluent in Django templates and can write them by himself, but
> still, I like Django for showing a clear way for designers and coders
> to work together.

This isn't an especially strong argument against including the view in
the template -- after all, the template language allows dot notation
to explore object attributes. The underlying type is completely opaque
from a template designer's perspective.

Yours,
Russ Magee %-)

Russell Keith-Magee

unread,
Sep 2, 2011, 4:04:41 AM9/2/11
to django-d...@googlegroups.com
On Fri, Sep 2, 2011 at 3:00 PM, Greg Donald <gdo...@gmail.com> wrote:
> On Thu, Sep 1, 2011 at 3:46 PM, Reinout van Rees <rei...@vanrees.org> wrote:
>> why does django encourage a hand-crafted
>> context dictionary instead of "just" passing the view object along?
>
> I think it's the worst part of using Django.  Having to manage a
> context dictionary in every view is weak.

To the best of my knowledge, the only reason the view isn't included
in the template context is because over more than two years of design
discussion, I don't think the idea of including the view in the
context was ever proposed.

It seems like a reasonable idea to me, though, and it should be
possible to accommodate in a backwards compatible fashion. The trivial
fix would be to add a 'view' variable to the default context. It might
also be possible to replace the default get_context_data
implementation with something that reflects the attributes of the view
object itself -- however, this will obviously require a bit more
design work to make sure there aren't any backwards incompatible
implications.

Patches welcome ;-)

Yours,
Russ Magee %-)

Reinout van Rees

unread,
Sep 2, 2011, 4:53:51 AM9/2/11
to django-d...@googlegroups.com
On 02-09-11 10:04, Russell Keith-Magee wrote:
> To the best of my knowledge, the only reason the view isn't included
> in the template context is because over more than two years of design
> discussion, I don't think the idea of including the view in the
> context was ever proposed.
[...]
> Patches welcome;-)

I haven't got a patch (yet), but I at least created a ticket for it:
https://code.djangoproject.com/ticket/16744

Carl Meyer

unread,
Sep 2, 2011, 12:35:41 PM9/2/11
to django-d...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 09/02/2011 01:01 AM, Greg Donald wrote:
> Planning for designers to work in code is an extreme edge case. In 15
> years of web development I've never once worked with a single designer
> who was interested in touching any code. As far as my own web
> projects go, the designer is done the moment they give me a layered
> .psd.

Please be careful with the unwarranted generalizations based on your
personal experience. I'm sure there are designers who never go beyond
the PSD, but my personal experience happens to be the opposite - I've
never worked with a web designer who didn't handle all of the HTML, CSS,
and templates themselves; almost all of the designers I know are
perfectly competent in front-end coding (and some in Python, too). It
seems a bit rude to dismiss them all as an "extreme edge case." If you'd
like to broaden your horizons, I'd be happy to recommend some names ;-)

> How is something like {{ view.myvar }} any harder than {{ myvar }} for
> those two designers in the whole world who actually want to touch the
> code?

I agree that {{ view.myvar }} is just fine.

But please lay off the overblown rhetoric. I can name fifteen designers
who code off the top of my head (more than I could name who don't).

Carl
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk5hBdwACgkQ8W4rlRKtE2dmjACfT9EURJhvwTLW/S21ak7TzXvI
U84AoMzbnDACXDf0oTVjtovcen+ybv+6
=Sz6+
-----END PGP SIGNATURE-----

Greg Donald

unread,
Sep 2, 2011, 5:15:19 PM9/2/11
to django-d...@googlegroups.com
On Fri, Sep 2, 2011 at 11:35 AM, Carl Meyer <ca...@oddbird.net> wrote:
> But please lay off the overblown rhetoric. I can name fifteen designers
> who code off the top of my head (more than I could name who don't).

Clearly you've been working with some hybrid wanna-be designers who
probably don't do any heavy lifting in either realm.


--
Greg Donald

Jacob Kaplan-Moss

unread,
Sep 2, 2011, 5:28:38 PM9/2/11
to django-d...@googlegroups.com
On Fri, Sep 2, 2011 at 4:15 PM, Greg Donald <gdo...@gmail.com> wrote:
> Clearly you've been working with some hybrid wanna-be designers who
> probably don't do any heavy lifting in either realm.

Greg, I hope and am going to assume you're joking. If not -- and
remember with email it can hard to tell -- this comes across as
super-insulting.

Either way, you guys are way off topic at this point. Take it to
private email, please.

Jacob

Luke Plant

unread,
Sep 3, 2011, 10:05:58 AM9/3/11
to django-d...@googlegroups.com
On 01/09/11 21:46, Reinout van Rees wrote:

> Passing the view object to the template by default seems to me to be an
> absolute no-brainer. Class based views ought to mean you get the view
> object in your template, right? But Django doesn't do it. So... is there
> a specific reason for it?

Like Russell, I'd never thought of this idea before. The main argument I
can think of against doing this is that it encodes an implementation
detail into your templates. A template shouldn't know whether the data
has come from a CBV or function, and shouldn't have to be changed if you
go from one to the other or back again (both transitions being sensible
in some circumstances). To me, this change would produce very strong
coupling between the presentation logic and the view that produced it.

The history of CBVs in Django is that they are simply a way of using OOP
and inheritance to reduce duplication between view functions and allow
better re-use. They are supposed to be drop in replacements for function
based views in terms of the end result, rather than produce any change
in what a template will contain. This means that CBVs and function based
views are both first class citizens in Django world, and I for one
prefer it that way.

Slight digression: I do not think that CBVs are obvious winners for
writing views. There are significant trade-offs and downsides, such as
ravioli code, as I've blogged about before [1]. I've recently written an
app from scratch using CBVs heavily, and it worked well, but 1) there
were still times that functions were better, 2) there were some
inheritance problems that required a small amount of fairly heavy-duty
metaclass hackery to solve, 3) the code is less transparent to a newcomer.

Regards,

Luke

[1] http://lukeplant.me.uk/blog/posts/class-based-views-and-dry-ravioli/


--
"Doubt: In the battle between you and the world, bet on the world."
(despair.com)

Luke Plant || http://lukeplant.me.uk/

Reinout van Rees

unread,
Sep 4, 2011, 3:28:43 PM9/4/11
to django-d...@googlegroups.com
On 03-09-11 16:05, Luke Plant wrote:
> The history of CBVs in Django is that they are simply a way of using OOP
> and inheritance to reduce duplication between view functions and allow
> better re-use. They are supposed to be drop in replacements for function
> based views in terms of the end result, rather than produce any change
> in what a template will contain.

Ok, when you want to keep the function and class based views more or
less the same, the current implementation makes sense.

On the other hand, from an object oriented viewpoint, the class based
views seem to be pretty powerless and non-object-oriented. To me, it
almost seems like they're artificially "castrated" to make function
views look good :-) That's probably not the intention, but...

Probably the best illustration of my point: .get_context_data() should
return a dictionary. And .render_to_response() needs the output of that.
"So" you have to pass the output of .get_context_data() to
.render_to_response(). Wait a minute... We're talking object orientation
here! Why doesn't .render_to_response() call .get_context_data()? This
is just function-like behaviour in a thin object oriented shell.

From an OO viewpoint, I'd rather expect a "self.context = {}" in the
most top-level view baseclass's __init__(). Not passing along a variable
that is calculated in the very same class as a parameter to a method in
that very same class.


Your point that, effectively, {{ view.something }} is different than {{
something}} is valid, though. In that sense, a class based view that
passes {'view': self} as the context dict isn't a drop-in replacement.

Would you be more happy with a more magical view that would inject
everything from local() into the context dictionary or something like that?

Reinout van Rees

unread,
Sep 4, 2011, 3:44:02 PM9/4/11
to django-d...@googlegroups.com
On 04-09-11 21:28, Reinout van Rees wrote:
> On the other hand, from an object oriented viewpoint, the class based
> views seem to be pretty powerless and non-object-oriented. To me, it
> almost seems like they're artificially "castrated" to make function
> views look good :-) That's probably not the intention, but...

Ehm, the current classes based views are pretty good, apart from the
view-not-in-context problem that I see.

That's the one point on which I find those CBV's to be somewhat powerless.

Upon re-reading it sounded a bit like I think the whole of class based
views is powerless and bad, but that was *totally* not my intention :-)
I love 'em :-)

Tobias

unread,
Sep 9, 2011, 6:15:39 PM9/9/11
to Django developers
On Sep 4, 12:44 pm, Reinout van Rees <rein...@vanrees.org> wrote:
> On 04-09-11 21:28, Reinout van Rees wrote:
>
> > On the other hand, from an object oriented viewpoint, the class based
> > views seem to be pretty powerless and non-object-oriented. To me, it
> > almost seems like they're artificially "castrated" to make function
> > views look good :-) That's probably not the intention, but...
>
> Ehm, the current classes based views are pretty good, apart from the
> view-not-in-context problem that I see.
>
> That's the one point on which I find those CBV's to be somewhat powerless.
>
> Upon re-reading it sounded a bit like I think the whole of class based
> views is powerless and bad, but that was *totally* not my intention :-)
> I love 'em :-)

This is probably an overly simplistic implementation, but would
something like this work, more broadly covering Jacob's concerns in
the ticket about template authors being able to shoot themselves in
the foot? It seems less effective to mark all required methods with
alters_data, as this method also wouldn't prevent get(), post(), etc.
from being called in subclassed views (which could potentially
generate recursive loops).

https://github.com/tobiasmcnulty/django/compare/master...ticket-16744

On a side note, I noticed that get_context_data in TemplateView
behaves differently than all the others, as it puts kwargs in a
'params' variable instead of copying the kwargs directly into the
context. Is this intentional? I'm not super-familiar with class
based generic views, but it seemed odd to me.

Cheers,
Tobias

Reinout van Rees

unread,
Sep 12, 2011, 11:39:03 AM9/12/11
to django-d...@googlegroups.com
On 10-09-11 00:15, Tobias wrote:
> This is probably an overly simplistic implementation, but would
> something like this work, more broadly covering Jacob's concerns in
> the ticket about template authors being able to shoot themselves in
> the foot? It seems less effective to mark all required methods with
> alters_data, as this method also wouldn't prevent get(), post(), etc.
> from being called in subclassed views (which could potentially
> generate recursive loops).
>
> https://github.com/tobiasmcnulty/django/compare/master...ticket-16744

It is already more elaborate than what I'm using locally now :-) I don't
have a proxy object in my own views. Seems like a good idea, though.

Addition: disallow attributes/methods starting with an underscore?
That's a handy way to stow away dangerous methods should you have them
in your view.

The only way I can see yourself shooting in the foot is when you have a
form view that reacts to get() and post(). Upon "get()", the template
*could* call data-modifying methods on the class.

Florian Apolloner

unread,
Sep 12, 2011, 12:25:01 PM9/12/11
to django-d...@googlegroups.com
On Monday, September 12, 2011 5:39:03 PM UTC+2, Reinout van Rees wrote:
Addition: disallow attributes/methods starting with an underscore? 

That's a handy way to stow away dangerous methods should you have them
in your view.

That's already the case for resolving variables in templates, I don't think we need any specialcasing here.


> The only way I can see yourself shooting in the foot is when you have a
> form view that reacts to get() and post(). Upon "get()", the template
> *could* call data-modifying methods on the class. 

Not easily, since the templates can only call methods which don't require extra params, get/post do take request at least.

Cheers,
Florian

Reinout van Rees

unread,
Sep 12, 2011, 2:10:49 PM9/12/11
to django-d...@googlegroups.com

I love it when problems solve themselves :-)

Tobias McNulty

unread,
Sep 13, 2011, 2:33:02 PM9/13/11
to django-d...@googlegroups.com
On Mon, Sep 12, 2011 at 2:10 PM, Reinout van Rees <rei...@vanrees.org> wrote:
On 12-09-11 18:25, Florian Apolloner wrote:
On Monday, September 12, 2011 5:39:03 PM UTC+2, Reinout van Rees wrote:

   Addition: disallow attributes/methods starting with an underscore?

   That's a handy way to stow away dangerous methods should you have them
   in your view.

That's already the case for resolving variables in templates, I don't
think we need any specialcasing here.

            > The only way I can see yourself shooting in the foot is
           when you have a
            > form view that reacts to get() and post(). Upon "get()",
           the template

                > *could* call data-modifying methods on the class.


Not easily, since the templates can only call methods which don't
require extra params, get/post do take request at least.

I love it when problems solve themselves :-)

That's a good point.  Are there *any* methods in the CBVs that don't take arguments, that also modify data?  The only one that I found in the list I'd initially proposed that can be called without arguments is as_view(), and I'm not sure that really even needs protection.  Maybe there's no need to protect anything with alters_data / proxying?

That would certainly be the simplest, and would eliminate the possibility that someone will later ask for us to expose a certain method or attribute that we thought it best to hide now.

Tobias
--
Tobias McNulty, Managing Member
Caktus Consulting Group, LLC
http://www.caktusgroup.com

Reinout van Rees

unread,
Sep 13, 2011, 3:28:40 PM9/13/11
to django-d...@googlegroups.com
On 13-09-11 20:33, Tobias McNulty wrote:
> I love it when problems solve themselves :-)
>
>
> That's a good point. Are there *any* methods in the CBVs that don't
> take arguments, that also modify data? The only one that I found in the
> list I'd initially proposed that can be called without arguments is
> as_view(), and I'm not sure that really even needs protection. Maybe
> there's no need to protect anything with alters_data / proxying?

There's not really anything useful you can do with as_view in your
template, should you attempt it. I also don't think you can do anything
destructive with it.

So it sounds like we don't need the proxy. Good that you added it anyway
as it helps us dig deeper into the problem :-) Luckily it seems we don't
have to dig very deep.

Roald de Vries

unread,
Sep 15, 2011, 5:23:57 AM9/15/11
to django-d...@googlegroups.com

On Sep 13, 2011, at 9:28 PM, Reinout van Rees wrote:

> On 13-09-11 20:33, Tobias McNulty wrote:
>> I love it when problems solve themselves :-)
>>
>>
>> That's a good point. Are there *any* methods in the CBVs that don't
>> take arguments, that also modify data? The only one that I found
>> in the
>> list I'd initially proposed that can be called without arguments is
>> as_view(), and I'm not sure that really even needs protection. Maybe
>> there's no need to protect anything with alters_data / proxying?
>
> There's not really anything useful you can do with as_view in your
> template, should you attempt it. I also don't think you can do
> anything destructive with it.

as_view() is a classonlymethod, which gives an AttributeError when
called on an instance, so putting an instance of the cbv in the
context seems fine for as far as this is concerned.

Reply all
Reply to author
Forward
0 new messages