views:

98

answers:

1

I'm writing a couple of Jinja2 templates that basically implement some common grid layouts. I'd like to be able to share this 'library' of templates between a Pylons app and Django app.

I've hit a minor stumbling block in that Django's template context is accessible from the "top-level" of the template, whereas Pylons wraps your context inside the thread local c (or tmpl_context) variable.

Here are some analogous examples that demonstrate this.

Django

from django.shortcuts import render_to_response

ctx = {}
ctx['name'] = 'John'

return render_to_response('hello.html', ctx)

hello.html:

Hello {{ name }}

Pylons

from pylons import tmpl_context as c
from myapp.lib.base import render

c.name = 'John'
return render('hello.html') 

hello.html:

Hello {{ c.name }}

What I'm trying to do is make it so that hello.html is the same across both frameworks.

One way I see to do it is by wrapping the Django render_to_response and do something like this:

ctx['c'] = ctx

But that just doesn't feel right. Anybody see other alternatives to this?

Thanks

+1  A: 

How dated is your version of Pylons? render seems to be deprecated in favor of render_jinja2. Granted, the Jinja2 documentation mislabels it as render_jinja, and the Pylons documentation doesn't show it at all, but the Pylons 1.0 source code does include it and imply its usage.

Or if you're stuck with an older version of Pylons, you can exploit the fact that setting c.name is the same as setting c.__dict__['name'], and similarly for all its attributes. This makes it easy to set all of c's attributes if you have the ctx dict handy.

ctx = {'name': 'John'}

# Django
from django.shortcuts import render_to_response
render_to_response('hello.html', ctx)

# old Pylons?
from pylons import tmpl_context as c
from pylons.templating import render
c.__dict__.update(ctx)
render('hello.html')

# new Pylons
from pylon.templating import render_jinja2
render_jinja2('hello.html', ctx)

Also, I'm surprised that the old Pylons named the variable in the template based on what you named the object that you imported. Are you sure that c isn't passed as an argument to render?

Disclaimer: I don't have Django or Pylons installed, so I can't test either of my suggestions.

Nikhil Chelliah
I am using Pylons 1.0. The function `myapp.lib.base.render` calls `render_jinja2` under the hood. Pylons generated this wrapper when I created my project and I told it to use Jinja2.
Joe Holloway
Also, Pylons makes the context available to the template as both `tmpl_context` (legacy) and `c` (recommended). How you import that module into your controller doesn't really impact how it is named in the template as far as I can tell. It doesn't have to be passed as an argument because Pylons uses some thread-local voodoo to make module-level things work on a per-request basis. In other words, I could have imported it as `ctx` or whatever in my module, but Pylons would still make it available as `tmpl_context` and `c` to my template.
Joe Holloway
I see...I guess I don't know much about Pylons code. Does `__dict__.update` help? What happens if you call `render_jinja2` directly?
Nikhil Chelliah
I'm a little confused because at some level, Jinja2 **does** accept `**kwargs`, so there must be a way to pass them instead of going through `c`. Worst case, you could just use the Jinja2 API to render the templates yourself, and manually pass `c`, `c.__dict__`, `ctx`, etc.
Nikhil Chelliah
I haven't done it yet, but I think the solution is going to involve tweaking the Django side to let the context processors execute, then take the resulting context and make it available to the templates as `c` so that it mimics what Pylons does. That's if I want to keep using `render_jinja2` as-is which works with the thread-local voodoo. Or, I could probably implement my own version of Pylons' `render_jinja2` that puts the thread-local context directly as the context instead of passing it in as `c` or `tmpl_context`. I'll post an update if I get it working.
Joe Holloway