Caching XHTML render_to_response

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import django.shortcuts
from django.http import HttpResponse
from django.template import loader
from django.template.context import Context

template_cache = { }
def render_to_response(*args, **kwargs) :
  """Implement two changes relative to django.shortcuts.render_to_response:
       1) Use content-type 'application/xhtml+xml' if supported by the client.
       2) Cache the compiled template.
  """

  # Set content type to application/xhtml+xml if conditions allow.
  if not kwargs.has_key('mimetype') and \
     kwargs.has_key('context_instance') and \
     kwargs['context_instance'].has_key('request') and \
     kwargs['context_instance']['request'].META.has_key('HTTP_ACCEPT') and \
     'application/xhtml+xml' in \
       kwargs['context_instance']['request'].META['HTTP_ACCEPT'].split(',') :
    kwargs['mimetype'] = 'application/xhtml+xml'

  # Load template (use cache if possible).
  template_path = args[0]
  if template_cache.has_key(template_path) :
    template = template_cache[template_path]
  else :
    template = loader.get_template(template_path)
    template_cache[template_path] = template

  # Render template using provided context.
  if kwargs.has_key('context_instance') :
    context_instance = kwargs['context_instance']
  else :
    context_instance = Context()

  if len(args) > 1 :
    context_instance.update(args[1])

  rendering = template.render(context_instance)

  # Return HttpResponse using rendered template.
  httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
  return HttpResponse(rendering, **httpresponse_kwargs)

More like this

  1. XhtmlDegraderMiddleware by dmh 6 years, 8 months ago
  2. Mobilize your Django site by stevena0 5 years ago
  3. Accept Header Middleware by kioopi 6 years ago
  4. SQLLoggerMidleware + infobar by robvdl 6 years, 3 months ago
  5. Unobtrusive comment moderation by ubernostrum 7 years, 1 month ago

Comments

adamlofts (on July 23, 2008):

Hmmm.. Templates are already precompiled by django. I don't think this will make the code any faster. Have you benchmarked it?

#

smoonen (on July 23, 2008):

Hi adam. From my reading of the code in django.template.loader and django.template.loaders.filesystem, it seems to me that template files are loaded from disk on each request. So I think that my code is saving both the file load and also the template compile on every subsequent request.

Can you point me to something that shows otherwise? I certainly don't want to add unnecessary overhead! Thanks.

In my particular case this code did yield some performance improvement. I have much more significant bottlenecks still to track down, though.

#

smoonen (on July 23, 2008):

Ok, here are some more formal results. I wrote two scripts, test.py:

from django.shortcuts import render_to_response
for i in range(1000) :
  render_to_response('myapp/index.html')

and test2.py:

from myapp.util import render_to_response
for i in range(1000) :
  render_to_response('myapp/index.html')

From the command line:

$ time python test.py

real    0m27.097s
user    0m26.886s
sys     0m0.212s
$ time python test2.py

real    0m22.528s
user    0m22.329s
sys     0m0.200s

#

adamlofts (on July 24, 2008):

Ah! Your right that the template loaders do attempt to open the template name every time. One might hope that the kernel will have them cached once its warmed up a bit; but you're right (and your test demonstrates) that there is a performance increase.

#

(Forgotten your password?)