When I render a moderately complex dictionary (4 levels deep, ~2K data points) using django 1.4's default template system the template rendering step takes over 2800ms. When I do html-gen directly from python instead it takes ~80ms. Even using another template library (jinja2) renders the same data (in fact, almost exactly the same template syntax - as jinja2 is nearly a drop-in replacement) in under 300ms.
Interestingly, you don't even have to actually render the dictionary in the template to cause this performance issue in django's template system... all you have to do is pass it as an available variable to a template. A friend of mine suggested this may mean the system is, "...doing a defensive copy or (more stupidly) a comprehension [which] will take time due to running constructors"
Anyone know why django's default template system takes so long to render dictionaries?
* I'll work on adding requested details below *
I am running in debug mode and have the DebugToolbarMiddleware set as one of my middleware classes. My settings.py file includes:
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',
)
and....
# rendering like this
return render(
request,
template_name='ltm/search_results.html',
context_instance=RequestContext(request, {
'menus': menus,
'results': result_dict
})
)
Django templates are slow compared to Jinja2 templates. This may be to do with Jinja2 compiling the templates or perhaps due to the excessive number of function calls Django makes while rendering templates.
The most significant implication is Jinja being extremely slow when parsing templates with segments of whitespace in tens of thousands.
Rendering means interpolating the template with context data and returning the resulting string. The Django template language is Django's own template system. Until Django 1.8 it was the only built-in option available. It's a good template library even though it's fairly opinionated and sports a few idiosyncrasies.
It would be great if you could provide us with your template code to better understand what kind of template processing we're dealing with exactly.
Firstly, there are potential differences between how your traversing the contents of the dictionary. dict.items()
returns a list of tuples which consumes additional memory and takes time to initially construct, but it's faster to access keys and values than through a generator if you used dict.iteritems()
.
There's also some overhead involved when you pass in variable names preceded by a dot .
, e.g. foo.bar.baz
, where Django's template performs what's called a variable lookup, trying to determine whether your accessing a dictionary item by key, an object's attribute or a list item by index. I haven't used Jinja2, so the issue with variable lookups might be completely unrelated, but it is something worth considering if there's a difference between the two.
In either case, since your dealing with a fairly large dictionary, it might help if you could reorganize it's structure in the view to simplify how the data is accessed later in the template.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With