idea for using RequestContext by default

10 views
Skip to first unread message

Wim Feijen

unread,
Dec 30, 2009, 5:28:57 PM12/30/09
to Django developers
Hello,

In the discussions on CSRF there have been several proposals to
include RequestContext by default in render_to_response or in a
similar function. As a side note to my previous post, I'd like to
mention my favorite way to do this: render_to , see:

http://www.djangosnippets.org/snippets/821/

Best regards,

Wim Feijen

Will LaShell

unread,
Dec 30, 2009, 6:23:30 PM12/30/09
to django-d...@googlegroups.com
On Wed, 2009-12-30 at 14:28 -0800, Wim Feijen wrote:
> Hello,
>
> In the discussions on CSRF there have been several proposals to
> include RequestContext by default in render_to_response or in a
> similar function. As a side note to my previous post, I'd like to
> mention my favorite way to do this: render_to , see:

The generic view function direct_to_template already handles this
need. If anything we could add a line in the documentation or tutorials
pointing this usage out.

Simon Willison

unread,
Jan 2, 2010, 5:52:08 PM1/2/10
to Django developers

So here's how that's supposed to work:

@render_to('my/template.html')
def my_view(request, param):
return {'data': 'some_data'}

I have to admit I don't understand the appeal of this syntax at all.
How is it any better than this? :

def my_view(request, param):
return render('my/template.html', {'data': 'some_data'})

The decorator implementation is more complicated, makes debugging
trickier (since decorators confuse stack traces and other debugging
tools) and doesn't save any typing. What are the advantages?

I'm a big fan of decorators for things like caching/memoization, but I
don't understand why they provide any advantage for the above. I'm not
a fan of the current @permalink decorator in Django for the same
reason - if a decorator simply changes the syntax for how arguments
are passed to a function, what's the point of using them?

Cheers,

Simon

Yuri Baburov

unread,
Jan 3, 2010, 7:18:29 AM1/3/10
to django-d...@googlegroups.com
Hi Simon,

Readability is all about lots of tiny details.

I suppose you meant this:
def my_view(request, param):
return render('my/template.html', {'data': 'some_data'}, request)

This decorator intercepts `request` argument.
When you have 2 or more ways to return anything from function, it
looks much better.
Moreover, visually it looks much better too: this important
information of what page is rendered to each template is always right
here.

@render_to('my/template.html')
def my_view(request, param):

if param == 'something':
return {'data': 'some_data'}
elif something_else():
return HttpResponse('not found anything at all')
else:
return {'data': 'some_other_data'}, 'another/template.html'

What both render_to decorator and render() still miss, is extendability.
I think, Django still misses a lot when it comes to views/templates
extensibility.
Look at 3rd-party apps or django contribs. You can freely use their
models, but 90% of cases you can't reuse their views.

def your_view(request, param):
if param == 'something2':
return login(request, template='login.html') +
{'additional_key':'additional_value'} # how do I do this?!
else:
return my_view(request, param, template='your/template.html')
+ {'additional_key':'additional_value'} # or how do I do this?

How to make these lines of code effective and readable at all?
Some views don't provide template= option, some call it differently...

You are now only able to add middleware to extend already generated
HttpResponses.
I think, RequestContext was made to make such extendability more
simple, but it was (almost?) never used in that way.

We had discussion both about this issue and
render_to/render/render_to_response already in django-developers.
http://groups.google.com/group/django-developers/browse_frm/thread/f53fea4a0551ab7c/64956c854776f4e8
Still not found excellent solution.

--
Best regards, Yuri V. Baburov, ICQ# 99934676, Skype: yuri.baburov,
MSN: bu...@live.com

buttman

unread,
Jan 4, 2010, 12:57:26 PM1/4/10
to Django developers

I much prefer the @render_to() syntax. This way, I can think of my
view functions as "context variable creators", instead of "response
returners". I think of view functions as a sort of context processor
thats only meant for one specific template.

Almost every single view I have ever written (more or less) follows
this pattern:

process stuff into variables -> add said variables to a ContextRequest
-> send said ContextRequest to a template for rendering.

With @render_to, it allows me to delegate all the rendering crap to
the decorator, while the view function gets to focus on what is really
there for; creating extra variables to be passed on to the template.
It makes things simpler for me and adds readability.

Also, I've never had a problem with the decorator messing up
tracebacks.

Russell Keith-Magee

unread,
Jan 4, 2010, 7:11:17 PM1/4/10
to django-d...@googlegroups.com

I'm in complete agreement with Simon on this point. I fail to see the
benefit of decorators in this context. However, it's easy to find
several negative points:

* The "accept a request, return a response" view contract makes
sense, and is consistent with other layers in the Django stack.
* Special handling is required in the decorator when a view needs to
return HttpResponseRedirect (or any other non-template-rendered
response). This says nothing for the case where you need to return a
non-200 response *and* templated content.
* The return value for views becomes a tuple with a convention,
rather than an explicit single (response) object.

So - I'm fairly confident in saying that this isn't going to happen in
Django trunk.

However, this position doesn't prevent you from using this approach in
your own code, so if you're a fan of using decorators in this way,
feel free to do so.

Yours,
Russ Magee %-)

buttman

unread,
Jan 4, 2010, 9:28:49 PM1/4/10
to Django developers
> > I much prefer the @render_to() syntax. This way, I can think of my
> > view functions as "context variable creators", instead of "response
> > returners". I think of view functions as a sort of context processor
> > thats only meant for one specific template.
>
> I'm in complete agreement with Simon on this point. I fail to see the
> benefit of decorators in this context. However, it's easy to find
> several negative points:
>
>  * The "accept a request, return a response"  view contract makes
> sense, and is consistent with other layers in the Django stack.
>  * Special handling is required in the decorator when a view needs to
> return HttpResponseRedirect (or any other non-template-rendered
> response). This says nothing for the case where you need to return a
> non-200 response *and* templated content.

I actually just checked one of my views, and the version of @render_to
that comes with django-annoying does indeed let you return
ResponseRedirect objects. For an example, look at this code:

http://github.com/nbv4/flightloggin/blob/master/logbook/views.py

which is currently in production and it works fine. If request.POST
exists, it will save a form and then issue a ResponseRedirect,
otherwise, it'll create some variables and then return locals(), which
the decorator will then handle.

>  * The return value for views becomes a tuple with a convention,
> rather than an explicit single (response) object.

I don't understand this part. tuples? With the decorator views return
dictionaries.

> So - I'm fairly confident in saying that this isn't going to happen in
> Django trunk.

Fine with me. Either I import it from annoying.decorators or
django.shortcuts, it don't make no difference to me...

rebus_

unread,
Jan 5, 2010, 6:06:06 AM1/5/10
to django-d...@googlegroups.com
Hi,

This is the "natural" sequence of doing things anyway, i don't see why
would you shuffle it around.

1. process stuff into variables
2. add said variables to a ContextRequest
3. send said ContextRequest to a template for rendering.

In the example buttman gave in his link [1] you could say you don't
even need to specify a template. You could just have a decorator that
says "this function is a view and when it returns take the name of the
function and generate template name or even if it is ajax request
append _ajax to template name". This is however even more implicit,
though it could save you some typing.

[1] http://github.com/nbv4/flightloggin/blob/master/logbook/views.py


> This decorator intercepts `request` argument.
> When you have 2 or more ways to return anything from function, it
> looks much better.
> Moreover, visually it looks much better too: this important

> information of what page is rendered to each template is always right
> here.

Personally I don't find this readable at all:

@render_to('my/template.html')
def my_view(request, param):

if param == 'something':
return {'data': 'some_data'}
elif something_else():
return HttpResponse('not found anything at all')
else:
return {'data': 'some_other_data'}, 'another/template.html'

You explicitly set a template at the beginning of the view but few
lines after it you mention yet another template.
When someone is reading your code this could lead to confusion. What
happens when you need to debug lets say few hundred line view? You
could even forget that you used another template in it and pull your
hair out why my/template.html doesn't produce wanted result.

Also, it doesn't either look or work much more different then:

def my_view(request, param)
template = 'my/template.html'
if param == 'something':
context = {'some':context}
elif something_else():
context = {'some_other':context}
template = 'another/template.html'
return render_to_response(template, context,
context_instance=RequestContext(request))

Just my 2 cents,

--
Davor Lučić

Yuri Baburov

unread,
Jan 5, 2010, 7:12:13 AM1/5/10
to django-d...@googlegroups.com
Hi Davor,

On Tue, Jan 5, 2010 at 5:06 PM, rebus_ <r.da...@gmail.com> wrote:
> Hi,
>
> This is the "natural" sequence of doing things anyway, i don't see why
> would you shuffle it around.
>
> 1. process stuff into variables
> 2. add said variables to a ContextRequest
> 3. send said ContextRequest to a template for rendering.

Nothing is shuffled around.
But we came to a bikeshed discussion.

Please, no imaginary arguments.

> Also, it doesn't either look or work much more different then:
>
> def my_view(request, param)
>  template = 'my/template.html'
>  if param == 'something':
>    context = {'some':context}
>  elif something_else():
>    context = {'some_other':context}
>    template = 'another/template.html'
>  return render_to_response(template, context,
> context_instance=RequestContext(request))

Compare to:
@render_to()


def my_view(request, param)
template = 'my/template.html'
if param == 'something':
context = {'some':context}
elif something_else():
context = {'some_other':context}
template = 'another/template.html'

return context, template

render_to is made to translate
"return render_to_response(template, context,
context_instance=RequestContext(request))"
into "return context, template".

If you like the longer version, or don't see the difference, what else to talk?

In bikeshed question of what to use, render_to or render_to_response(),
the winner is clearly the smarter render shortcut, proposed in different thread.
"render(template, context, request)".

Ivan Sagalaev

unread,
Jan 5, 2010, 8:23:44 AM1/5/10
to django-d...@googlegroups.com
Russell Keith-Magee wrote:
> I'm in complete agreement with Simon on this point. I fail to see the
> benefit of decorators in this context.

I can see one valid point that "render_to" guys have. Which is,
incidentally, has nothing to do with the decorator syntax. An
HttpResponse with an opaque string as its content is hard to alter after
it is returned from a view (one of the precedents was the old
CsrfMiddleware was parsing HTML to inject a token). And most of the real
use-cases for this are about adding something to the view's context
before it blends in a template. Right now the only way to do it is with
context processors but they are global, not per-view, which is not
convenient.

I think it can be solved another way, by something like a special
HttpResponse subclass -- TemplateResponse. It can keep a template and
its context separate until the very last moment when its contents is
asked and only then do render a template.

This will allow extension of the views:

# some library:

def library_view(request):
# ...
return TemplateReponse('template.html', context = { ... })

# user code:

def my_view(request):
response = library_view(request)
response.context.update({ ... })
return response

Russel, can you see something like this in Django trunk?

Russell Keith-Magee

unread,
Jan 5, 2010, 8:41:54 AM1/5/10
to django-d...@googlegroups.com

Certainly - and Simon made exactly this proposal during the review of
the CSRF work. Simon even provided a sample implementation:

http://groups.google.com/group/django-developers/msg/b1b3f8854b9ae2b1

(Ignore the bits about the CSRF implementation - the interesting bits
are near the end of the message)

I haven't taken the temperature of anyone else in the core, but you
can take it as read that Simon and myself are both +1. The sprint this
weekend would be a great opportunity to advocate for inclusion of
this. With a few tests and documentation, Simon's patch could easily
be made trunk-ready.

Yours,
Russ Magee %-)

Ivan Sagalaev

unread,
Jan 5, 2010, 9:53:05 AM1/5/10
to django-d...@googlegroups.com
Russell Keith-Magee wrote:
> Certainly - and Simon made exactly this proposal during the review of
> the CSRF work. Simon even provided a sample implementation:
>
> http://groups.google.com/group/django-developers/msg/b1b3f8854b9ae2b1

Thanks! I keep missing nice things on django-dev@ due to many *-dev
lists traffic :-(

Jacob Kaplan-Moss

unread,
Jan 5, 2010, 10:00:21 AM1/5/10
to django-d...@googlegroups.com
On Tue, Jan 5, 2010 at 7:41 AM, Russell Keith-Magee
<freakb...@gmail.com> wrote:
> I haven't taken the temperature of anyone else in the core, but you
> can take it as read that Simon and myself are both +1. The sprint this
> weekend would be a great opportunity to advocate for inclusion of
> this. With a few tests and documentation, Simon's patch could easily
> be made trunk-ready.

I'm also +1 on something like ``TemplateResponse``, and especially
``django.shortcuts.render(request, template, context)``.

Jacob

Ben Firshman

unread,
Jan 5, 2010, 10:35:06 AM1/5/10
to django-d...@googlegroups.com

I ran across a really frustrating problem with TemplateResponse.

TemplateResponses typically get baked by a response middleware because
that's the first place the content is accessed. However, if there are
any template errors, you don't see a sensible traceback because pretty
debug pages aren't shown for exceptions raised in middleware.

Is there any reason why exceptions in middleware aren't handled?

Ben

Russell Keith-Magee

unread,
Jan 5, 2010, 10:38:37 AM1/5/10
to django-d...@googlegroups.com

To clarify your position Jacob - are you advocating that
shortcuts.render() should return a TemplateReponse? Or are you
suggesting that we add a TemplateResponse *and* a shortcut.render()
that is an analog of render_to_response, but with a RequestContext?

Russ %-)

Jacob Kaplan-Moss

unread,
Jan 5, 2010, 11:20:10 AM1/5/10
to django-d...@googlegroups.com
On Tue, Jan 5, 2010 at 9:38 AM, Russell Keith-Magee
<freakb...@gmail.com> wrote:
> To clarify your position Jacob - are you advocating that
> shortcuts.render() should return a TemplateReponse? Or are you
> suggesting that we add a TemplateResponse *and* a shortcut.render()
> that is an analog of render_to_response, but with a RequestContext?

I don't particularly care how ``render`` works internally -- I'm not
totally sold on ``TemplateResponse``, but I'm also not against it
really. I'm just really sick of
``context_instance=RequestContext(request)``.

Jacob

Reply all
Reply to author
Forward
0 new messages