Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django templatetag scope forcing me to do extra queries

Tags:

The problem is that if I call a templatetag into a block and it fills me a variiable with the usual context[varname]=something, then if I need that variable into another block, I have to call the templatetag again. This for me means extra db queries, which is really something I'm trying to avoid.

This templatetag is called in a base template which is extended by many other templates, so I can't just change all the views to pass something to the context, it makes no sense (WET principle?)

Even a context processor would be not good because I don't want to call it for every page rendered in the site, even the ones not based on that template.

I was thinking about writing a templatetag which would use the internal context structures to put the variable in a global context, but I'd feel too guilty doing it.

How would you solve this problem?

like image 746
Alex Rades Avatar asked Jan 16 '10 10:01

Alex Rades


1 Answers

You said, "This templatetag is called in a base template which is extended by many other templates."

The question is: is this tag called from within a named block? If it is then you have a couple of potential problems.

  1. {% block %} pushes a new dict on the Context stack and pops it off when it reaches the matching `{% endblock %}'. This means any context value created while in the block has essentially gone out of scope on block exit.

  2. If this block is overridden by some other template that extends the base template, the value may not be available at all unless you do a {{block.super}}, and even then I'm not certain the value will be available to the template doing the extending.

If the tag is not called from within a {% block %} then the context value should be available to all of the code that follows it, either in the base template, any included templates and (I think) any extending templates.

This is one of those cases where building a set of careful tests will probably save you time and tears.

Alternatively, if you are always accessing this value, you could just put it in a context processor so that its availability is guaranteed.

Update for comments: OK, time to bring in the big guns! One of the most irritating, long-standing bugs in Django templates is that callables (ie. functions) that are top-level context values (as opposed to functions that are dict-values/methods of context values) are not called! This ticket is over 2 years old and takes about 10 lines of code to fix. We have several heavy-weight DB calls that we only want to happen if the template cache has expired. So we a) MonkeyPatched the template _resolve_lookup() code to fix the callable problem, and then b) curry functions to have all of the necessary parameters if needed, because you can't pass params to functions in the template "language".

like image 190
Peter Rowell Avatar answered Oct 14 '22 03:10

Peter Rowell