{"title":"执行原生 SQL 查询","version":"3.1","locale":"zh-hans","docname":"topics/db/sql","url":"/zh-hans/3.1/topics/db/sql/","canonical":"https://djangodocs.dev/zh-hans/3.1/topics/db/sql/","summary":"Django 允许你用两种方式执行原生 SQL 查询：你可以使用 Manager.raw() 来 执行原生查询并返回模型实例 ，或者完全不用模型层 直接执行自定义 SQL 。 在使用原生 SQL 之前探索 ORM！ Django ORM 提供了很多工具，允许你在不编写原生 SQL 的情况下表达查询。例如： QuerySet…","html":"<h1>执行原生 SQL 查询<a class=\"heading-anchor\" href=\"#performing-raw-sql-queries\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 允许你用两种方式执行原生 SQL 查询：你可以使用 <a class=\"reference internal\" href=\"#django.db.models.Manager.raw\" title=\"django.db.models.Manager.raw\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Manager.raw()</span></code></a> 来 <a class=\"reference internal\" href=\"#performing-raw-queries\">执行原生查询并返回模型实例</a>，或者完全不用模型层  <a class=\"reference internal\" href=\"#executing-custom-sql-directly\">直接执行自定义 SQL</a>。</p>\n<aside class=\"admonition-explore-the-orm-before-using-raw-sql admonition\">\n<p class=\"admonition-title\">在使用原生 SQL 之前探索 ORM！</p>\n<p>Django ORM 提供了很多工具，允许你在不编写原生 SQL 的情况下表达查询。例如：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/querysets/\"><span class=\"doc\">QuerySet API</span></a> 覆盖面很广。</p></li>\n<li><p>你可以用很多内置的 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/database-functions/\"><span class=\"doc\">数据库函数</span></a> 进行 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/querysets/#django.db.models.query.QuerySet.annotate\" title=\"django.db.models.query.QuerySet.annotate\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">annotate</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/db/aggregation/\"><span class=\"doc\">aggregate</span></a>。除此之外，你还可以创建 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/expressions/\"><span class=\"doc\">查询表达式</span></a>。</p></li>\n</ul>\n<p>Before using raw SQL, explore <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/db/\"><span class=\"doc\">the ORM</span></a>. Ask on\none of <a class=\"reference internal\" href=\"/zh-hans/3.1/faq/help/\"><span class=\"doc\">the support channels</span></a> to see if the ORM supports\nyour use case.</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>无论何时编写原生 SQL 都要万分小心。使用时，你要用 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 将任何用户传入的参数进行安全转义，避免 SQL 注入攻击。阅读 <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/security/#sql-injection-protection\"><span class=\"std std-ref\">SQL 注入保护</span></a> 了解更多。</p>\n</aside>\n<section id=\"performing-raw-queries\">\n<span id=\"executing-raw-queries\"></span><h2>执行原生查询<a class=\"heading-anchor\" href=\"#performing-raw-queries\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>若管理器方法 <code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code> 能用于执行原生 SQL 查询，就会返回模型实例：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.db.models.Manager.raw\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">Manager.</span></span><span class=\"sig-name descname\"><span class=\"pre\">raw</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">raw_query</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">params</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">translations</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.db.models.Manager.raw\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>该方法接受一个原生 SQL 查询语句，执行它，并返回一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.db.models.query.RawQuerySet</span></code> 实例。这个 <code class=\"docutils literal notranslate\"><span class=\"pre\">RawQuerySet</span></code> 能像普通的 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/querysets/#django.db.models.query.QuerySet\" title=\"django.db.models.query.QuerySet\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code></a> 一样被迭代获取对象实例。</p>\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\">class</span><span class=\"w\"> </span><span class=\"nc\">Person</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">first_name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n    <span class=\"n\">last_name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n    <span class=\"n\">birth_date</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>然后你可以像这样执行自定义 SQL:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">p</span> <span class=\"ow\">in</span> <span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT * FROM myapp_person&#39;</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"p\">)</span>\n<span class=\"go\">John Smith</span>\n<span class=\"go\">Jane Jones</span>\n</code></pre></div>\n<p>这个例子并不令人激动——它与运行 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person.objects.all()</span></code> 完全相同。然而， <code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code> 有很多额外选项，使得它非常强大。</p>\n<aside class=\"admonition-model-table-names admonition\">\n<p class=\"admonition-title\">模型表名</p>\n<p>在本例中， <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 表的名称是从哪来的？</p>\n<p>默认情况下，Django 通过拼接模型的 &quot;app label&quot; 和模型类名推算出数据表名 —— 即你在 <code class=\"docutils literal notranslate\"><span class=\"pre\">manage.py</span> <span class=\"pre\">startapp</span></code> 中使用的名称，二者以一个下划线分割。在本例中，我们假定 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 模型位于一个叫做 <code class=\"docutils literal notranslate\"><span class=\"pre\">myapp</span></code> 的应用中，这样，模型的表名就是 <code class=\"docutils literal notranslate\"><span class=\"pre\">myapp_person</span></code>。</p>\n<p>更多细节请查阅关于 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/options/#django.db.models.Options.db_table\" title=\"django.db.models.Options.db_table\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">db_table</span></code></a> 选项的文档，它也允许你手动指定数据库的表名。</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>不会对传给 <code class=\"docutils literal notranslate\"><span class=\"pre\">.raw()</span></code> 的 SQL 语句做任何检查。Django 期望该语句会从数据库中返回一个集合，但并不强制如此。若该查询没有返回一些记录，会导致一个（含糊）的错误。</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>若你在 MySQL 上执行查询，至于其无声的强制类型可能会弄混类型时导致不可预料的后果。若你用一个整数值查询一个字符串列，MySQL 会执行比较前将表中所有数据强制转为整数。例如，若数据表包含的值有 <code class=\"docutils literal notranslate\"><span class=\"pre\">'abc'</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">'def'</span></code>，而查询语句为 <code class=\"docutils literal notranslate\"><span class=\"pre\">WHERE</span> <span class=\"pre\">mycolumn=0</span></code>，这两行都会匹配上。要避免这种情况，在将值传给查询语句前进行合适的类型转换。</p>\n</aside>\n<section id=\"mapping-query-fields-to-model-fields\">\n<h3>将查询字段映射为模型字段<a class=\"heading-anchor\" href=\"#mapping-query-fields-to-model-fields\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code> 字段将查询语句中的字段映射至模型中的字段。</p>\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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT id, first_name, last_name, birth_date FROM myapp_person&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">...</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT last_name, birth_date, first_name, id FROM myapp_person&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">...</span>\n</code></pre></div>\n<p>匹配是根据名字来的。这意味着你可以使用 SQL 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">AS</span></code> 子句将查询语句中的字段映射至模型中的字段。所以，若你还有一些数据表包含了 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 数据，你可以很方便的将其映射至 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 实例:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;&#39;&#39;SELECT first AS first_name,</span>\n<span class=\"gp\">... </span><span class=\"s1\">                             last AS last_name,</span>\n<span class=\"gp\">... </span><span class=\"s1\">                             bd AS birth_date,</span>\n<span class=\"gp\">... </span><span class=\"s1\">                             pk AS id,</span>\n<span class=\"gp\">... </span><span class=\"s1\">                      FROM some_other_table&#39;&#39;&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>只要名字对上了，模型实例就会被正确创建。</p>\n<p>或者，你可以用 <code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">translations</span></code> 参数将查询语句中的字段映射至模型中的字段。这是一个字典，将查询语句中的字段名映射至模型中的字段名。例如，上面的查询也能这样写:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">name_map</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;first&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;first_name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;last&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;last_name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;bd&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;birth_date&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;pk&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;id&#39;</span><span class=\"p\">}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT * FROM some_other_table&#39;</span><span class=\"p\">,</span> <span class=\"n\">translations</span><span class=\"o\">=</span><span class=\"n\">name_map</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"index-lookups\">\n<h3>索引查询<a class=\"heading-anchor\" href=\"#index-lookups\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code> 支持索引，所以，若你只需要第一个结果就这样写:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">first_person</span> <span class=\"o\">=</span> <span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT * FROM myapp_person&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>不过，索引和切片不是在数据库层面上实现的。若数据库中有非常多的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 对象，更搞笑的方式是在 SQL 层面使用 limit 子句:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">first_person</span> <span class=\"o\">=</span> <span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT * FROM myapp_person LIMIT 1&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</code></pre></div>\n</section>\n<section id=\"deferring-model-fields\">\n<h3>延迟模型字段<a class=\"heading-anchor\" href=\"#deferring-model-fields\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">people</span> <span class=\"o\">=</span> <span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT id, first_name FROM myapp_person&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>该查询返回的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 对象即延迟模型实例（参考 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/querysets/#django.db.models.query.QuerySet.defer\" title=\"django.db.models.query.QuerySet.defer\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">defer()</span></code></a>）。这意味着查询语句中省略的字段按需加载。例子:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">p</span> <span class=\"ow\">in</span> <span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT id, first_name FROM myapp_person&#39;</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">first_name</span><span class=\"p\">,</span> <span class=\"c1\"># This will be retrieved by the original query</span>\n<span class=\"gp\">... </span>          <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">last_name</span><span class=\"p\">)</span> <span class=\"c1\"># This will be retrieved on demand</span>\n<span class=\"gp\">...</span>\n<span class=\"go\">John Smith</span>\n<span class=\"go\">Jane Jones</span>\n</code></pre></div>\n<p>表面上，看起来该查询同时检出了 first name 和 last name。然而，这个例子实际上执行了三次查询。只有 first names 是由 raw() 查询检出的 —— last names 是在它们被打印时按需检出。</p>\n<p>只有一个字段你不能省略 —— 主键字段。Django 用主键来区分模型实例，所以必须在原生查询语句中包含主键。若你忘了包含主键会抛出 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/exceptions/#django.core.exceptions.FieldDoesNotExist\" title=\"django.core.exceptions.FieldDoesNotExist\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">FieldDoesNotExist</span></code></a>  异常。</p>\n</section>\n<section id=\"adding-annotations\">\n<h3>添加注释<a class=\"heading-anchor\" href=\"#adding-annotations\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>你可以执行带有模型中未定义字段的查询语句。例如，我们能用 <a class=\"reference external\" href=\"https://www.postgresql.org/docs/current/functions-datetime.html\">PostgreSQL 的 age() 函数</a> 获取用户列表，他们的年龄已由数据库计算:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">people</span> <span class=\"o\">=</span> <span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT *, age(birth_date) AS age FROM myapp_person&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">p</span> <span class=\"ow\">in</span> <span class=\"n\">people</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> is </span><span class=\"si\">%s</span><span class=\"s2\">.&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">first_name</span><span class=\"p\">,</span> <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">age</span><span class=\"p\">))</span>\n<span class=\"go\">John is 37.</span>\n<span class=\"go\">Jane is 42.</span>\n<span class=\"go\">...</span>\n</code></pre></div>\n<p>你总是可以用 <a class=\"reference internal\" href=\"/zh-hans/3.1/ref/models/expressions/#func-expressions\"><span class=\"std std-ref\">Func() 表达式</span></a> 避免使用原生 SQL 去计算注释。</p>\n</section>\n<section id=\"passing-parameters-into-raw\">\n<h3>将参数传给 <code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code><a class=\"heading-anchor\" href=\"#passing-parameters-into-raw\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你需要执行参数化的查询，可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">raw()</span></code> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 参数:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">lname</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Doe&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"s1\">&#39;SELECT * FROM myapp_person WHERE last_name = </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"n\">lname</span><span class=\"p\">])</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 是一个参数字典。你将用一个列表替换查询字符串中 <code class=\"docutils literal notranslate\"><span class=\"pre\">%s</span></code> 占位符，或用字典替换 <code class=\"docutils literal notranslate\"><span class=\"pre\">%(key)s</span></code> 占位符（<code class=\"docutils literal notranslate\"><span class=\"pre\">key</span></code> 被字典 key 替换），不论你使用哪个数据库引擎。这些占位符会被 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 参数的值替换。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>使用 SQLite 后端时不支持字典参数；使用此后端时，你必须以列表形式传入参数。</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p><strong>不要对原生查询或 SQL 字符串中的引号占位符使用字符串格式化！</strong></p>\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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">query</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;SELECT * FROM myapp_person WHERE last_name = </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"n\">lname</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Person</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">raw</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>你可能认为你需要将查询写成这样（用单引号包裹 <code class=\"docutils literal notranslate\"><span class=\"pre\">%s</span></code>）:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">query</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;SELECT * FROM myapp_person WHERE last_name = &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span>\n</code></pre></div>\n<p><strong>不要犯其它错误。</strong></p>\n<p>正如 <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/security/#sql-injection-protection\"><span class=\"std std-ref\">防御 SQL 注入</span></a> 介绍的，使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> 参数和不用引号包裹占位符使你免受 <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/SQL_injection\">SQL 注入攻击</a>，这是一个攻击者常用的漏洞，将任意 SQL 注入你的数据库。若你使用了字符串插入或用引号包裹占位符，你正处于 SQL 注入的风险中。</p>\n</aside>\n</section>\n</section>\n<section id=\"executing-custom-sql-directly\">\n<span id=\"executing-custom-sql\"></span><h2>直接执行自定义 SQL<a class=\"heading-anchor\" href=\"#executing-custom-sql-directly\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有时候，甚至 <a class=\"reference internal\" href=\"#django.db.models.Manager.raw\" title=\"django.db.models.Manager.raw\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Manager.raw()</span></code></a> 都无法满足需求：你可能要执行不明确映射至模型的查询语句，或者就是直接执行 <code class=\"docutils literal notranslate\"><span class=\"pre\">UPDATE</span></code>， <code class=\"docutils literal notranslate\"><span class=\"pre\">INSERT</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">DELETE</span></code> 语句。</p>\n<p>这些情况下，你总是能直接访问数据库，完全绕过模型层。</p>\n<p>对象 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.db.connection</span></code> 代表默认数据库连接。要使用这个数据库连接，调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">connection.cursor()</span></code> 来获取一个指针对象。然后，调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">cursor.execute(sql,</span> <span class=\"pre\">[params])</span></code> 来执行该 SQL 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">cursor.fetchone()</span></code>，或 <code class=\"docutils literal notranslate\"><span class=\"pre\">cursor.fetchall()</span></code> 获取结果数据。</p>\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=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_custom_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"k\">with</span> <span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">()</span> <span class=\"k\">as</span> <span class=\"n\">cursor</span><span class=\"p\">:</span>\n        <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;UPDATE bar SET foo = 1 WHERE baz = </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">baz</span><span class=\"p\">])</span>\n        <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;SELECT foo FROM bar WHERE baz = </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">baz</span><span class=\"p\">])</span>\n        <span class=\"n\">row</span> <span class=\"o\">=</span> <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">fetchone</span><span class=\"p\">()</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">row</span>\n</code></pre></div>\n<p>要避免 SQL 注入，你绝对不能在 SQL 字符串中用引号包裹  <code class=\"docutils literal notranslate\"><span class=\"pre\">%s</span></code> 占位符。</p>\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=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;SELECT foo FROM bar WHERE baz = &#39;30%&#39;&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;SELECT foo FROM bar WHERE baz = &#39;30</span><span class=\"si\">%%</span><span class=\"s2\">&#39; AND id = </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>若你同时使用 <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/db/multi-db/\"><span class=\"doc\">不止一个数据库</span></a>，你可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.db.connections</span></code> 获取指定数据库的连接（和指针）。 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.db.connections</span></code> 是一个类字典对象，它允许你通过连接别名获取指定连接:</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\">connections</span>\n<span class=\"k\">with</span> <span class=\"n\">connections</span><span class=\"p\">[</span><span class=\"s1\">&#39;my_db_alias&#39;</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">()</span> <span class=\"k\">as</span> <span class=\"n\">cursor</span><span class=\"p\">:</span>\n    <span class=\"c1\"># Your code here...</span>\n</code></pre></div>\n<p>默认情况下，Python DB API 返回的结果不会包含字段名，这意味着你最终会收到一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">list</span></code>，而不是一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">dict</span></code>。要追求较少的运算和内存消耗，你可以以 <code class=\"docutils literal notranslate\"><span class=\"pre\">dict</span></code> 返回结果，通过使用如下的玩意:</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\">dictfetchall</span><span class=\"p\">(</span><span class=\"n\">cursor</span><span class=\"p\">):</span>\n    <span class=\"s2\">&quot;Return all rows from a cursor as a dict&quot;</span>\n    <span class=\"n\">columns</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">col</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">col</span> <span class=\"ow\">in</span> <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">description</span><span class=\"p\">]</span>\n    <span class=\"k\">return</span> <span class=\"p\">[</span>\n        <span class=\"nb\">dict</span><span class=\"p\">(</span><span class=\"nb\">zip</span><span class=\"p\">(</span><span class=\"n\">columns</span><span class=\"p\">,</span> <span class=\"n\">row</span><span class=\"p\">))</span>\n        <span class=\"k\">for</span> <span class=\"n\">row</span> <span class=\"ow\">in</span> <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">fetchall</span><span class=\"p\">()</span>\n    <span class=\"p\">]</span>\n</code></pre></div>\n<p>另一个选项是使用来自 Python 标准库的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/collections.html#collections.namedtuple\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">collections.namedtuple()</span></code></a>。 <code class=\"docutils literal notranslate\"><span class=\"pre\">namedtuple</span></code> 是一个类元组对象，可以通过属性查找来访问其包含的字段；也能通过索引和迭代。结果都是不可变的，但能通过字段名或索引访问，这很实用:</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\">collections</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">namedtuple</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">namedtuplefetchall</span><span class=\"p\">(</span><span class=\"n\">cursor</span><span class=\"p\">):</span>\n    <span class=\"s2\">&quot;Return all rows from a cursor as a namedtuple&quot;</span>\n    <span class=\"n\">desc</span> <span class=\"o\">=</span> <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">description</span>\n    <span class=\"n\">nt_result</span> <span class=\"o\">=</span> <span class=\"n\">namedtuple</span><span class=\"p\">(</span><span class=\"s1\">&#39;Result&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"n\">col</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">col</span> <span class=\"ow\">in</span> <span class=\"n\">desc</span><span class=\"p\">])</span>\n    <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">nt_result</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">row</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">row</span> <span class=\"ow\">in</span> <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">fetchall</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=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;SELECT id, parent_id FROM test LIMIT 2&quot;</span><span class=\"p\">);</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">fetchall</span><span class=\"p\">()</span>\n<span class=\"go\">((54360982, None), (54360880, None))</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;SELECT id, parent_id FROM test LIMIT 2&quot;</span><span class=\"p\">);</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">dictfetchall</span><span class=\"p\">(</span><span class=\"n\">cursor</span><span class=\"p\">)</span>\n<span class=\"go\">[{&#39;parent_id&#39;: None, &#39;id&#39;: 54360982}, {&#39;parent_id&#39;: None, &#39;id&#39;: 54360880}]</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"s2\">&quot;SELECT id, parent_id FROM test LIMIT 2&quot;</span><span class=\"p\">);</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">results</span> <span class=\"o\">=</span> <span class=\"n\">namedtuplefetchall</span><span class=\"p\">(</span><span class=\"n\">cursor</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">results</span>\n<span class=\"go\">[Result(id=54360982, parent_id=None), Result(id=54360880, parent_id=None)]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">results</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">id</span>\n<span class=\"go\">54360982</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">results</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n<span class=\"go\">54360982</span>\n</code></pre></div>\n<section id=\"connections-and-cursors\">\n<h3>连接和指针<a class=\"heading-anchor\" href=\"#connections-and-cursors\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">connection</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">cursor</span></code> 实现了 <span class=\"target\" id=\"index-2\"></span><a class=\"pep reference external\" href=\"https://peps.python.org/pep-0249/\"><strong>PEP 249</strong></a> 中介绍的大部分标准 Python DB-API —— 除了 <a class=\"reference internal\" href=\"/zh-hans/3.1/topics/db/transactions/\"><span class=\"doc\">事务处理</span></a> 之外。</p>\n<p>若你并不熟悉 Python DB-API，要注意 <code class=\"docutils literal notranslate\"><span class=\"pre\">cursor.execute()</span></code> 中的 SQL 语句使用了占位符 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;%s&quot;</span></code>，而不是直接在 SQL 中添加参数。若你使用这个技巧，潜在的数据库库会自动在需要时转义参数。</p>\n<p>也要注意，Django 期望 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;%s&quot;</span></code> 占位符，而 <em>不是</em> <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;?&quot;</span></code> 占位符，后者由 SQLite Python 绑定使用。这是为了一致性和正确性。</p>\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\">with</span> <span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">()</span> <span class=\"k\">as</span> <span class=\"n\">c</span><span class=\"p\">:</span>\n    <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"o\">...</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=\"n\">c</span> <span class=\"o\">=</span> <span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">()</span>\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">execute</span><span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n<span class=\"k\">finally</span><span class=\"p\">:</span>\n    <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n</code></pre></div>\n<section id=\"calling-stored-procedures\">\n<h4>调用存储流程<a class=\"heading-anchor\" href=\"#calling-stored-procedures\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.db.models.CursorWrapper.callproc\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">CursorWrapper.</span></span><span class=\"sig-name descname\"><span class=\"pre\">callproc</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">procname</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">params</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">kparams</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.db.models.CursorWrapper.callproc\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>以给定名称调用数据库存储流程。要提供一个序列 (<code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code>) 或字典 (<code class=\"docutils literal notranslate\"><span class=\"pre\">kparams</span></code>) 作为输入参数。大多数数据库不支持 <code class=\"docutils literal notranslate\"><span class=\"pre\">kparams</span></code>。对于 Django 内置后端来说，只有 Oracle 支持。</p>\n<p>例如，在一个 Oracle 数据库中指定存储流程：</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</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=\"SQL code\"><code><span class=\"k\">CREATE</span><span class=\"w\"> </span><span class=\"k\">PROCEDURE</span><span class=\"w\"> </span><span class=\"ss\">&quot;TEST_PROCEDURE&quot;</span><span class=\"p\">(</span><span class=\"n\">v_i</span><span class=\"w\"> </span><span class=\"nb\">INTEGER</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"n\">v_text</span><span class=\"w\"> </span><span class=\"n\">NVARCHAR2</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">))</span><span class=\"w\"> </span><span class=\"k\">AS</span>\n<span class=\"w\">    </span><span class=\"n\">p_i</span><span class=\"w\"> </span><span class=\"nb\">INTEGER</span><span class=\"p\">;</span>\n<span class=\"w\">    </span><span class=\"n\">p_text</span><span class=\"w\"> </span><span class=\"n\">NVARCHAR2</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">);</span>\n<span class=\"k\">BEGIN</span>\n<span class=\"w\">    </span><span class=\"n\">p_i</span><span class=\"w\"> </span><span class=\"p\">:</span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"n\">v_i</span><span class=\"p\">;</span>\n<span class=\"w\">    </span><span class=\"n\">p_text</span><span class=\"w\"> </span><span class=\"p\">:</span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"n\">v_text</span><span class=\"p\">;</span>\n<span class=\"w\">    </span><span class=\"p\">...</span>\n<span class=\"k\">END</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=\"k\">with</span> <span class=\"n\">connection</span><span class=\"o\">.</span><span class=\"n\">cursor</span><span class=\"p\">()</span> <span class=\"k\">as</span> <span class=\"n\">cursor</span><span class=\"p\">:</span>\n    <span class=\"n\">cursor</span><span class=\"o\">.</span><span class=\"n\">callproc</span><span class=\"p\">(</span><span class=\"s1\">&#39;test_procedure&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s1\">&#39;test&#39;</span><span class=\"p\">])</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n</section>\n</section>","rootId":"performing-raw-sql-queries","toc":[{"title":"执行原生查询","anchor":"performing-raw-queries","children":[{"title":"将查询字段映射为模型字段","anchor":"mapping-query-fields-to-model-fields","children":[]},{"title":"索引查询","anchor":"index-lookups","children":[]},{"title":"延迟模型字段","anchor":"deferring-model-fields","children":[]},{"title":"添加注释","anchor":"adding-annotations","children":[]},{"title":"将参数传给 raw()","anchor":"passing-parameters-into-raw","children":[]}]},{"title":"直接执行自定义 SQL","anchor":"executing-custom-sql-directly","children":[{"title":"连接和指针","anchor":"connections-and-cursors","children":[{"title":"调用存储流程","anchor":"calling-stored-procedures","children":[]}]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/3.1/topics/"},{"docname":"topics/db/index","title":"模型和数据库","url":"/zh-hans/3.1/topics/db/"}],"prev":{"docname":"topics/db/managers","title":"管理器","url":"/zh-hans/3.1/topics/db/managers/"},"next":{"docname":"topics/db/transactions","title":"数据库事务","url":"/zh-hans/3.1/topics/db/transactions/"},"formats":{"html":"/zh-hans/3.1/topics/db/sql/","markdown":"/zh-hans/3.1/topics/db/sql.md","json":"/zh-hans/3.1/topics/db/sql.json"},"source":"https://github.com/django/django/blob/stable/3.1.x/docs/topics/db/sql.txt","official":"https://docs.djangoproject.com/zh-hans/3.1/topics/db/sql/","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","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}