Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: display time it took to load a page on every page

Tags:

python

django

In Django, how can I return the time it took to load a page (not the date) in every page of the site, without having to write in every views.py a code similar to the following one?

start = time.time() #model operations loadingpagetime = time.time() - start 

If using a TEMPLATE_CONTEXT_PROCESSOR is the best option.
How would I get the whole page loading time from there, instead of just getting the template loading time?

UPDATE:

As the initial question doesn't seem to be clear enough, here is an approach of what would be the Python version of what I want to do.

#!/usr/bin/env python import cgitb; cgitb.enable()  import time print 'Content-type: text/html\n\n'  start = time.time()  print '<html>' print '<head>' print '</head>' print '<body>' print '<div>HEADER</div>' print '<div>' print '<p>Welcome to my Django Webpage!</p>' print '<p>Welcome to my Django Webpage!</p>' print '<p>Welcome to my Django Webpage!</p>' print '</div>'  time.sleep(3) loadingtime = time.time() - start  print '<div>It took ',loadingtime,' seconds to load the page</div>' print '</body>' print '</html>' 
like image 692
zurfyx Avatar asked Jul 19 '13 16:07

zurfyx


1 Answers

You can create a custom middleware to log this. Here is how I create a middleware to achieve this purpose base on http://djangosnippets.org/snippets/358/ (I modified the code a bit).

Firstly, assuming your project has a name: test_project, create a file name middlewares.py, I place it in the same folder as settings.py:

from django.db import connection from time import time from operator import add import re   class StatsMiddleware(object):      def process_view(self, request, view_func, view_args, view_kwargs):         '''         In your base template, put this:         <div id="stats">         <!-- STATS: Total: %(total_time).2fs Python: %(python_time).2fs DB: %(db_time).2fs Queries: %(db_queries)d ENDSTATS -->         </div>         '''          # Uncomment the following if you want to get stats on DEBUG=True only         #if not settings.DEBUG:         #    return None          # get number of db queries before we do anything         n = len(connection.queries)          # time the view         start = time()         response = view_func(request, *view_args, **view_kwargs)         total_time = time() - start          # compute the db time for the queries just run         db_queries = len(connection.queries) - n         if db_queries:             db_time = reduce(add, [float(q['time'])                                    for q in connection.queries[n:]])         else:             db_time = 0.0          # and backout python time         python_time = total_time - db_time          stats = {             'total_time': total_time,             'python_time': python_time,             'db_time': db_time,             'db_queries': db_queries,         }          # replace the comment if found         if response and response.content:             s = response.content             regexp = re.compile(r'(?P<cmt><!--\s*STATS:(?P<fmt>.*?)ENDSTATS\s*-->)')             match = regexp.search(s)             if match:                 s = (s[:match.start('cmt')] +                      match.group('fmt') % stats +                      s[match.end('cmt'):])                 response.content = s          return response 

Secondly, modify settings.py to add your middleware:

MIDDLEWARE_CLASSES = (     'django.middleware.common.CommonMiddleware',     'django.middleware.csrf.CsrfViewMiddleware',     # ... your existing middlewares ...      # your custom middleware here     'test_project.middlewares.StatsMiddleware', ) 

Note: you have to add the full path to your middleware class like above, the format is:

<project_name>.<middleware_file_name>.<middleware_class_name> 

A second note is I added this middleware to the end of the list because I just want to log the template load time alone. If you want to log the load time of templates + all middlewares, please put it in the beginning of MIDDLEWARE_CLASSES list (credits to @Symmitchry).

Back to the main topic, the next step is to modify your base.html or whatever pages you want to log load time, add this:

<div id="stats"> <!-- STATS: Total: %(total_time).2fs Python: %(python_time).2fs DB: %(db_time).2fs Queries: %(db_queries)d ENDSTATS --> </div> 

Note: you can name the <div id="stats"> and use CSS for that div however you want, but DON'T change the comment <!-- STATS: .... -->. If you want to change it, be sure that you test it against the regex pattern in the created middlewares.py.

Voila, enjoy the statistics.

EDIT:

For those who use CBVs (Class Based Views) a lot, you might have encountered the error ContentNotRenderedError with above solution. Have no fear, here is the fix in middlewares.py:

    # replace the comment if found     if response:         try:             # detects TemplateResponse which are not yet rendered             if response.is_rendered:                 rendered_content = response.content             else:                 rendered_content = response.rendered_content         except AttributeError:  # django < 1.5             rendered_content = response.content         if rendered_content:             s = rendered_content             regexp = re.compile(                 r'(?P<cmt><!--\s*STATS:(?P<fmt>.*?)ENDSTATS\s*-->)'             )             match = regexp.search(s)             if match:                 s = (s[:match.start('cmt')] +                      match.group('fmt') % stats +                      s[match.end('cmt'):])                 response.content = s      return response 

I got it working with Django 1.6.x, if you have problem with other version of Django, please ping me in comment section.

like image 134
Hieu Nguyen Avatar answered Sep 23 '22 01:09

Hieu Nguyen