{"title":"数据库工具","version":"6.0","locale":"zh-hans","docname":"topics/db/instrumentation","url":"/zh-hans/6.0/topics/db/instrumentation/","canonical":"https://djangodocs.dev/zh-hans/6.0/topics/db/instrumentation/","summary":"为了帮助你更好的理解并控制由你的代码所产生的数据库查询,Django提供了一个钩子函数,在这个钩子函数中你可以在数据库查询方法外层添加一层wrappers方法.举例说明, wrappers方法可以记录数据库查询的数量, 计算查询持续的事件, 为查询记录日志,…","html":"<h1>数据库工具<a class=\"heading-anchor\" href=\"#database-instrumentation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>为了帮助你更好的理解并控制由你的代码所产生的数据库查询,Django提供了一个钩子函数,在这个钩子函数中你可以在数据库查询方法外层添加一层wrappers方法.举例说明, wrappers方法可以记录数据库查询的数量, 计算查询持续的事件, 为查询记录日志, 甚至可以阻止查询的执行(例如在渲染使用了预取的数据的模板时确保没有数据库查询被执行).</p>\n<p>装饰器是在 <a class=\"reference internal\" href=\"/zh-hans/6.0/topics/http/middleware/\"><span class=\"doc\">middleware</span></a> 之后建模的--它们是可调用的，并把其他调用作为它们的参数之一。它们调用可调用函数来调用（可能是包装的）数据库查询，并且它们可以围绕这个调用做一些工作。然而，它们通过用户代码来创建和安装，因此不需要独立像中间件这样的独立文件。</p>\n<p>wrapper方法的安装是在上下文管理器中完成的 -- 因此wrapper方法是暂时的, 也是针对于你代码里的某些特定逻辑的.</p>\n<p>正如上面提到的, 一个使用wrapper方法的例子是阻塞查询的执行. 类似的代码为:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">blocker</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n    <span class=\"k\">raise</span> <span class=\"ne\">Exception</span><span class=\"p\">(</span><span class=\"s2\">&quot;No database access allowed here.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>它可以被用在视图里阻止来自模板的查询，如下所示：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">connection</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">render</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"n\">context</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"o\">...</span><span class=\"p\">}</span>  <span class=\"c1\"># Code to generate context with all data.</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"o\">...</span>\n    <span class=\"k\">with</span> <span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">execute_wrapper</span><span class=\"p\">(</span><span class=\"n\">blocker</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">template_name</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>发给wrapper方法的参数是:</p>\n<ul class=\"simple\">\n<li><p>&quot;execute&quot; -- 一个可以被执行的对象, 使用剩下的参数触发来执行查询.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">sql</span></code> -- 一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">str</span></code>，要发送到数据库的SQL 查询。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> -- SQL命令行参数值的列表/二元组，或者列表集/二元组集的一个列表/二元组（如果包装过的调用是  <code class=\"docutils literal notranslate\"><span class=\"pre\">executemany()</span></code> 的话）。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">many</span></code> -- 一个布尔值，标识最终的调用是否是 <code class=\"docutils literal notranslate\"><span class=\"pre\">execute()</span></code> 还是 <code class=\"docutils literal notranslate\"><span class=\"pre\">executemany()</span></code> （以及 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 是否是一个值系列，还是一系列值的序列）。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">context</span></code> -- 一个字典，包含带有关于调用上下文的数据。</p></li>\n</ul>\n<p>使用这个参数，稍微复杂一点的阻塞函数包含在错误信息中的连接名：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">blocker</span><span class=\"p\">(</span><span class=\"n\">execute</span><span class=\"p\">,</span> <span class=\"n\">sql</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">many</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">):</span>\n    <span class=\"n\">alias</span> <span class=\"o\">=</span> <span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s2\">&quot;connection&quot;</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">alias</span>\n    <span class=\"k\">raise</span> <span class=\"ne\">Exception</span><span class=\"p\">(</span><span class=\"s2\">&quot;Access to database &#39;</span><span class=\"si\">{}</span><span class=\"s2\">&#39; blocked here&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">alias</span><span class=\"p\">))</span>\n</code></pre></div>\n<p>有关更完整的例子，一个查询日志器看起来像这样：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">time</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QueryLogger</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queries</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__call__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">execute</span><span class=\"p\">,</span> <span class=\"n\">sql</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">many</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">):</span>\n        <span class=\"n\">current_query</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;sql&quot;</span><span class=\"p\">:</span> <span class=\"n\">sql</span><span class=\"p\">,</span> <span class=\"s2\">&quot;params&quot;</span><span class=\"p\">:</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"s2\">&quot;many&quot;</span><span class=\"p\">:</span> <span class=\"n\">many</span><span class=\"p\">}</span>\n        <span class=\"n\">start</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">monotonic</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"n\">sql</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"p\">,</span> <span class=\"n\">many</span><span class=\"p\">,</span> <span class=\"n\">context</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">current_query</span><span class=\"p\">[</span><span class=\"s2\">&quot;status&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;error&quot;</span>\n            <span class=\"n\">current_query</span><span class=\"p\">[</span><span class=\"s2\">&quot;exception&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">e</span>\n            <span class=\"k\">raise</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">current_query</span><span class=\"p\">[</span><span class=\"s2\">&quot;status&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ok&quot;</span>\n            <span class=\"k\">return</span> <span class=\"n\">result</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">duration</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">monotonic</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">start</span>\n            <span class=\"n\">current_query</span><span class=\"p\">[</span><span class=\"s2\">&quot;duration&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">duration</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queries</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">current_query</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>要使用它，你可以创建一个日志器对象，并且将其作为装饰器来安装：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">connection</span>\n\n<span class=\"n\">ql</span> <span class=\"o\">=</span> <span class=\"n\">QueryLogger</span><span class=\"p\">()</span>\n<span class=\"k\">with</span> <span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">execute_wrapper</span><span class=\"p\">(</span><span class=\"n\">ql</span><span class=\"p\">):</span>\n    <span class=\"n\">do_queries</span><span class=\"p\">()</span>\n<span class=\"c1\"># Now we can print the log.</span>\n<span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">ql</span><span class=\"o\">.</span><span class=\"n\">queries</span><span class=\"p\">)</span>\n</code></pre></div>\n<section id=\"connection-execute-wrapper\">\n<h2><code class=\"docutils literal notranslate\"><span class=\"pre\">connection.execute_wrapper()</span></code><a class=\"heading-anchor\" href=\"#connection-execute-wrapper\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.db.backends.base.DatabaseWrapper.execute_wrapper\">\n<span class=\"sig-name descname\"><span class=\"pre\">execute_wrapper</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">wrapper</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.db.backends.base.DatabaseWrapper.execute_wrapper\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>返回一个上下文管理器，当进入时，会安装一个围绕数据库查询执行的装饰器，当离开时，会移除这个装饰器。装饰器是在本地线程的连接对象上安装的。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">wrapper</span></code> is a callable taking five arguments. It is called for every query\nexecution in the scope of the context manager, with arguments <code class=\"docutils literal notranslate\"><span class=\"pre\">execute</span></code>,\n<code class=\"docutils literal notranslate\"><span class=\"pre\">sql</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">many</span></code>, and <code class=\"docutils literal notranslate\"><span class=\"pre\">context</span></code> as described above. It's\nexpected to call <code class=\"docutils literal notranslate\"><span class=\"pre\">execute(sql,</span> <span class=\"pre\">params,</span> <span class=\"pre\">many,</span> <span class=\"pre\">context)</span></code> and return the return\nvalue of that call.</p>\n</section>","rootId":"database-instrumentation","toc":[{"title":"connection.execute_wrapper()","anchor":"connection-execute-wrapper","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/6.0/topics/"},{"docname":"topics/db/index","title":"模型和数据库","url":"/zh-hans/6.0/topics/db/"}],"prev":{"docname":"topics/db/optimization","title":"数据库访问优化","url":"/zh-hans/6.0/topics/db/optimization/"},"next":{"docname":"topics/db/fixtures","title":"辅助工具","url":"/zh-hans/6.0/topics/db/fixtures/"},"formats":{"html":"/zh-hans/6.0/topics/db/instrumentation/","markdown":"/zh-hans/6.0/topics/db/instrumentation.md","json":"/zh-hans/6.0/topics/db/instrumentation.json"},"source":"https://github.com/django/django/blob/stable/6.0.x/docs/topics/db/instrumentation.txt","official":"https://docs.djangoproject.com/zh-hans/6.0/topics/db/instrumentation/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}