【问题标题】:Django: display time it took to load a page on every pageDjango:显示在每个页面上加载页面所花费的时间
【发布时间】:2013-07-19 00:55:39
【问题描述】:

在 Django 中,如何在网站的每个页面中返回加载页面所用的时间(不是日期),没有 strong> 必须在每个 views.py 中编写类似于以下的代码?

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

如果使用TEMPLATE_CONTEXT_PROCESSOR 是最好的选择。
我如何从那里获得整个页面的加载时间,而不是仅仅获得模板加载时间?

更新:

由于最初的问题似乎不够清楚,这里是我想做的Python版本的方法。

#!/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>'

【问题讨论】:

  • 您可以在模板中写出占位符,然后在中间件中进行修改。但是,在您之后运行的任何中间件都可能花费任意时间,因此这不是一个准确的计数。如果您希望更准确地完成此操作,请在负载平衡器、反向代理或 Django 前面的任何东西中进行重写。
  • @JamesAylett 一个答案/例子将不胜感激。
  • 抱歉,没有时间写出来——中间件需要一些时间来编写和测试。祝你好运!
  • 好的,这里有一个潜在的问题。在呈现模板时,请求仍在进行中。从请求开始到呈现模板片段的时间是可行的,但如果一个响应中间件阻塞 30 秒,则无法将该数据包含在已经呈现的 HTML 中。就像@JamesAylett 所说,中间件处理的占位符是您将获得的最接近的占位符,但有很多警告。查看 django-debug-toolbar 的 .middleware 模块和 TimerDebugPanel 的源代码作为起点。

标签: python django


【解决方案1】:

您可以创建一个自定义middleware 来记录此内容。下面是我如何基于http://djangosnippets.org/snippets/358/ 创建一个中间件来实现这个目的(我稍微修改了代码)。

首先,假设你的项目有一个名字:test_project,创建一个文件名middlewares.py,我把它和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

其次,修改settings.py添加你的中间件:

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    # ... your existing middlewares ...

    # your custom middleware here
    'test_project.middlewares.StatsMiddleware',
)

注意:您必须像上面一样添加中间件类的完整路径,格式为:

<project_name>.<middleware_file_name>.<middleware_class_name>

第二个注意事项是我将此中间件添加到列表的末尾,因为我只想单独记录模板加载时间。如果要记录模板+所有中间件的加载时间,请将其放在MIDDLEWARE_CLASSES列表的开头(感谢@Symmitchry)。

回到主题,下一步就是修改你的base.html或者你想记录加载时间的任何页面,添加这个:

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

注意:您可以命名 &lt;div id="stats"&gt; 并根据需要使用 CSS 为该 div,但不要更改注释 &lt;!-- STATS: .... --&gt;。如果要更改它,请确保针对创建的 middlewares.py 中的正则表达式模式对其进行测试。

瞧,享受统计数据吧。

编辑:

对于那些经常使用 CBV(基于类的视图)的人,您可能在上述解决方案中遇到了错误 ContentNotRenderedError。别担心,这里是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

我在 Django 1.6.x 上使用它,如果您对其他版本的 Django 有问题,请在评论部分联系我。

【讨论】:

  • 处理其他 MIDDLEWARE_CLASSES 所花费的时间怎么样?
  • 我已经在上面的答案中提到过,请仔细阅读。
  • 针对每个响应编译和运行正则表达式会对性能造成重大影响。至少,将编译后的版本缓存在中间件中。
  • @HieuNguyen 如何使它与基于类的视图一起使用?内容尚未生成并引发ContentNotRenderedError
  • 注意!这个实现只是跳过了所有后续中间件的 process_view 方法。这可能不是预期的......
【解决方案2】:

Geordi 为您提供了请求周期中发生的所有事情的精彩细分。它是一个中间件,可生成完整的调用树,以准确显示发生了什么以及每个函数花费了多长时间。

看起来像这样:

强烈推荐:)

图片来源:http://evzijst.bitbucket.org/pycon.in

【讨论】:

    【解决方案3】:

    我可能是错的,但我记得的第一件事是 document.ready 和 ajax... 我不认为这是最好的解决方案,但它应该非常简单,不仅在 django 中实现,而且在其他任何地方实现。 当您在视图中处理请求时,您启动计时器,并且当触发 document.ready 时,您进行 ajax 调用以停止计时器。 但我应该承认@Hieu Nguyen 非常出色)

    【讨论】:

      【解决方案4】:

      如果您想向访问者显示页面加载信息,Hieu Nguyen 的回答将是一个不错的选择。但我也向您推荐一些好工具。

      因此,如果您仅出于开发目的需要此数据,请查看 django-debug-toolbar。它将附加一个漂亮的工具栏,其中包含每个页面的有用统计信息,包括数据库查询、模板渲染等所花费的时间。

      最后,如果您需要专业的 Djagno 分析工具,New Relic 可能是一个很好的选择。

      【讨论】:

        【解决方案5】:

        我已经升级了 middleware.py。简而言之,我们在基本模板中添加一些独特的文本,然后在中间件 process_response 中替换它。这种方法看起来有点棘手,但我们的生成时间更接近真实,而且我们对 javascript 没有问题。客户端的 Javascript 不能在第一个加载的页面上使用页面标题,只有创建 XHR 对象,然后获取页面。

        https://stackoverflow.com/a/35237632/2837890

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-22
          • 1970-01-01
          • 2015-11-17
          • 2015-11-01
          • 2016-03-18
          • 1970-01-01
          相关资源
          最近更新 更多