Django Toolbar helped me notice today that I was sending a ton of context to an include tag that we loop over about 400 times. The include template only needs one small variable, but we were sending some really big ones to it.
I’ve seen in other contexts that sending large objects around can harm performance, so I switched it from:
{% include "my_template.html" %}
To:
{% include "my_template.html with small_var=small_var only %}
This uses the only tag to ensure that the included template gets less context.
(More about the only tag here)
I’m curious:
- Is this considered best practice?
- Will this help performance?
If yes to both, I’ll be happy to make a note in the documentation. It currently doesn’t say anything about performance.
1 Like
Welcome @mlissner !
I love questions like this! This is a great question and got me thinking.
At first look, I’d say using only is going to generally decrease performance.
If you look at django.template.loader_tags.IncludeNode.render, you’ll see that by using it, the render function is calling the .new() method defined in django.template.context.Context method, which makes a copy of the existing Context object before clearing the user-data and replacing it with the defined values. On the other hand, using include with the existing context and additional variables results in it adding those variables to the existing Context object - a lot less work.
Whether or not this is an accurate statement depends a lot upon the context in which it’s being said. In the case of Django’s template rendering engine, you’re not copying or “moving” data here. You’re passing a reference to an object (a Context object) between function calls. The size of the data within that Context object is irrelevant.
I was curious enough by your post to do a little more research. I created an artificially large context (~ 65,000 elements), then tested (using timeit) 1,000,000 iterations of rendering a rather simple template with a simple include, both with adding two variables with the with clause, and one test using “only”, the other without.
The results were as I expected. Not using only was faster - by a fairly significant margin.
But, the absolute values of that difference is truly negligible. Whatever time is spent actually rendering the template is so much greater than the time spent handling the Context object itself that it’s not worth worrying about it under any circumstances.
To answer your other question:
This really depends upon the needs of the template being included. This isn’t something to be determined by any general principle or blanket policy. What you need in the context for that template is more important than any consideration like this.
3 Likes
Wow, lovely answer, thanks Ken!
I guess this means I get to move the goalposts. The other fun thing going on here is that django debug toolbar renders these big context variables 400 times, making my HTML page about 400,000 lines long! So, I guess that’s not great for developers, though I’m amused nobody else noticed this. 
But sounds like big picture use only if it’s handy, because Django is smart and just passes references instead of objects. Very cool.
Thank you!