{"title":"多数据库","version":"4.2","locale":"zh-hans","docname":"topics/db/multi-db","url":"/zh-hans/4.2/topics/db/multi-db/","canonical":"https://djangodocs.dev/zh-hans/4.2/topics/db/multi-db/","summary":"这个主题指南描述了 Django 对多数据库交互的支持。大部分的 Django 文档假设你进行的是单数据库交互。如果你想多数据库交互，则需要执行一些其他步骤。","html":"<h1>多数据库<a class=\"heading-anchor\" href=\"#multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>这个主题指南描述了 Django 对多数据库交互的支持。大部分的 Django 文档假设你进行的是单数据库交互。如果你想多数据库交互，则需要执行一些其他步骤。</p>\n<aside class=\"admonition admonition-seealso\" role=\"note\">\n<p class=\"admonition-title\">See also</p>\n<p>查看 <a class=\"reference internal\" href=\"/zh-hans/4.2/topics/testing/tools/#testing-multi-db\"><span class=\"std std-ref\">多数据库支持</span></a> 获取关于多数据库测试的信息。</p>\n</aside>\n<section id=\"defining-your-databases\">\n<h2>定义数据库<a class=\"heading-anchor\" href=\"#defining-your-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>首先告知 Django，你正在使用至少2个数据库服务。通过 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 配置来将指定的数据库链接放入一个字典，以此来映射数据库别名，数据库别名是在整个Django中引用特定数据库的一种方式。</p>\n<p>可以选择任意的数据库别名，但是``default`` 别名具有特殊意义。当没有数据库指定选择的时候，Django 使用带有  <code class=\"docutils literal notranslate\">default</code> 别名的数据库。</p>\n<p>接下来一个 <code class=\"docutils literal notranslate\">settings.py</code> 片段，定义了2个数据库——默认的 PostgreSQL 数据库和名叫 <code class=\"docutils literal notranslate\">users</code> 的 MySQL 数据库。</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>DATABASES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;app_data&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.postgresql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;postgres_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;s3krit&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"s2\">&quot;users&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;user_data&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;priv4te&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>如果 <code class=\"docutils literal notranslate\">default</code> 数据库的设计在项目中没有使用，那么你需要特别注意始终指定你所使用的数据库。Django 需要定义  <code class=\"docutils literal notranslate\">default</code> 数据库，但如果没有使用数据库的话，参数字典可以置空。这样，你必须为所有的模型，包括你所使用的任何 contrib 和第三方 app 设置 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-DATABASE_ROUTERS\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASE_ROUTERS</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>DATABASES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{},</span>\n    <span class=\"s2\">&quot;users&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;user_data&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;superS3cret&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"s2\">&quot;customers&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;customer_data&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_cust&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;veryPriv@ate&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>如果尝试访问在 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 设置中未定义的数据库，Django 将引发一个 <code class=\"docutils literal notranslate\">django.utils.connection.ConnectionDoesNotExist</code> 异常。</p>\n</section>\n<section id=\"synchronizing-your-databases\">\n<span id=\"synchronizing-multiple-databases\"></span><h2>同步数据库<a class=\"heading-anchor\" href=\"#synchronizing-your-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p><a href=\"#id1\"><span class=\"problematic\" id=\"id2\">:migrate:`migrate`</span></a> 管理命令一次只操作一个数据库。默认情况下，它操作的是 <code class=\"docutils literal notranslate\">default</code> 数据库，但通过提供 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#cmdoption-migrate-database\"><code class=\"xref std std-option docutils literal notranslate\">--database</code></a> 选项，你可以告诉它同步到不同的数据库。因此，在上面的第一个示例中要将所有模型同步到所有数据库，你需要调用：</p>\n<div class=\"code-block\" data-language=\"shell\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code>$ ./manage.py migrate\n$ ./manage.py migrate --database<span class=\"o\">=</span>users\n</code></pre></div>\n<p>如果不想每个应用同步到特定数据库，可以定义 <a class=\"reference internal\" href=\"#topics-db-multi-db-routing\"><span class=\"std std-ref\">database router</span></a> ，它实施限制特定模型可用性的策略。</p>\n<p>如果像上面的第二个示例那样，你将 <code class=\"docutils literal notranslate\">default</code> 数据库留空，那么每次运行 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">migrate</code></a> 时都必须提供一个数据库名称。省略数据库名称将会引发错误。对于第二个示例：</p>\n<div class=\"code-block\" data-language=\"shell\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code>$ ./manage.py migrate --database<span class=\"o\">=</span>users\n$ ./manage.py migrate --database<span class=\"o\">=</span>customers\n</code></pre></div>\n<section id=\"using-other-management-commands\">\n<h3>使用其他管理命令<a class=\"heading-anchor\" href=\"#using-other-management-commands\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>大部分 <code class=\"docutils literal notranslate\">django-admin</code> 命令像 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">migrate</code></a> 一样操作数据库——它们一次只操作一个数据库，使用  <code class=\"docutils literal notranslate\">--database</code>  来控制所要使用的数据库。</p>\n<p>这个规则的一个例外是 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#django-admin-makemigrations\"><code class=\"xref std std-djadmin docutils literal notranslate\">makemigrations</code></a> 命令。它验证数据库中的迁移历史，以便在创建新迁移之前发现现有迁移文件的问题（这可能是修改它们所产生）。默认情况下，它只检查 <code class=\"docutils literal notranslate\">default</code> 数据库，但建议在任何模型安装时，执行 <a class=\"reference internal\" href=\"#allow_migrate\" title=\"allow_migrate\"><code class=\"xref py py-meth docutils literal notranslate\">allow_migrate()</code></a> method of <a class=\"reference internal\" href=\"#topics-db-multi-db-routing\"><span class=\"std std-ref\">routers</span></a> 。</p>\n</section>\n</section>\n<section id=\"automatic-database-routing\">\n<span id=\"topics-db-multi-db-routing\"></span><h2>自动数据库路由<a class=\"heading-anchor\" href=\"#automatic-database-routing\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>使用多数据库最简单的方式就是设置数据库路由方案。默认路由方案确保对象对原始数据库保持粘性（比如，从 <code class=\"docutils literal notranslate\">foo</code> 数据库检索到的对象将被保持到同一个数据库）。默认路由方案确保当数据库没有指定时，所有查询回退到  <code class=\"docutils literal notranslate\">default</code> 数据库。</p>\n<p>你无需执行任何操作来激活默认路由——在每个 Django 项目上是开箱即用的。然而，如果想实现更多有趣的数据库分配行为，可以定义和安装自己的数据库路由。</p>\n<section id=\"database-routers\">\n<h3>数据库路由<a class=\"heading-anchor\" href=\"#database-routers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>数据库路由是一个类，它提供四种方法：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"db_for_read\">\n<span class=\"sig-name descname\">db_for_read</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">model</em>, <em class=\"sig-param\"><span class=\"o\">**</span>hints</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#db_for_read\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>建议用于读取“模型”类型对象的数据库。</p>\n<p>如果数据库操作可以提供有助于选择数据库的任何附加信息，它将在 <code class=\"docutils literal notranslate\">hints</code>  中提供。这里 <a class=\"reference internal\" href=\"#topics-db-multi-db-hints\"><span class=\"std std-ref\">below</span></a> 提供了有效提示的详细信息。</p>\n<p>如果没有建议，则返回 <code class=\"docutils literal notranslate\">None</code> 。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"db_for_write\">\n<span class=\"sig-name descname\">db_for_write</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">model</em>, <em class=\"sig-param\"><span class=\"o\">**</span>hints</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#db_for_write\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>建议用于写入模型类型对象的数据库。</p>\n<p>如果数据库操作可以提供有助于选择数据库的任何附加信息，它将在 <code class=\"docutils literal notranslate\">hints</code>  中提供。这里 <a class=\"reference internal\" href=\"#topics-db-multi-db-hints\"><span class=\"std std-ref\">below</span></a> 提供了有效提示的详细信息。</p>\n<p>如果没有建议，则返回 <code class=\"docutils literal notranslate\">None</code> 。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"allow_relation\">\n<span class=\"sig-name descname\">allow_relation</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">obj1</em>, <em class=\"sig-param\">obj2</em>, <em class=\"sig-param\"><span class=\"o\">**</span>hints</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#allow_relation\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果允许 <code class=\"docutils literal notranslate\">obj1</code> 和 <code class=\"docutils literal notranslate\">obj2</code> 之间的关系，返回 <code class=\"docutils literal notranslate\">True</code> 。如果阻止关系，返回 <code class=\"docutils literal notranslate\">False</code> ，或如果路由没意见，则返回 <code class=\"docutils literal notranslate\">None</code>。这纯粹是一种验证操作，由外键和多对多操作决定是否应该允许关系。</p>\n<p>如果没有路由有意见（比如所有路由返回 <code class=\"docutils literal notranslate\">None</code>），则只允许同一个数据库内的关系。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"allow_migrate\">\n<span class=\"sig-name descname\">allow_migrate</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">db</em>, <em class=\"sig-param\">app_label</em>, <em class=\"sig-param\">model_name<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>hints</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#allow_migrate\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>决定是否允许迁移操作在别名为 <code class=\"docutils literal notranslate\">db</code> 的数据库上运行。如果操作运行，那么返回 <code class=\"docutils literal notranslate\">True</code> ，如果没有运行则返回 <code class=\"docutils literal notranslate\">False</code> ，或路由没有意见则返回 <code class=\"docutils literal notranslate\">None</code> 。</p>\n<p><code class=\"docutils literal notranslate\">app_label</code> 参数是要迁移的应用程序的标签。</p>\n<p><code class=\"docutils literal notranslate\">model_name</code> 由大部分迁移操作设置来要迁移的模型的 <code class=\"docutils literal notranslate\">model._meta.model_name</code> （模型 <code class=\"docutils literal notranslate\">__name__</code> 的小写版本） 的值。 对于 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/migration-operations/#django.db.migrations.operations.RunPython\" title=\"django.db.migrations.operations.RunPython\"><code class=\"xref py py-class docutils literal notranslate\">RunPython</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/migration-operations/#django.db.migrations.operations.RunSQL\" title=\"django.db.migrations.operations.RunSQL\"><code class=\"xref py py-class docutils literal notranslate\">RunSQL</code></a> 操作的值是 <code class=\"docutils literal notranslate\">None</code> ，除非它们提示要提供它。</p>\n<p><code class=\"docutils literal notranslate\">hints</code> 通过某些操作来向路由传达附加信息。</p>\n<p>当设置 <code class=\"docutils literal notranslate\">model_name</code> ，<code class=\"docutils literal notranslate\">hints</code> 通常包含  <code class=\"docutils literal notranslate\">'model'</code> 下的模型类。注意它可能是 <a class=\"reference internal\" href=\"/zh-hans/4.2/topics/migrations/#historical-models\"><span class=\"std std-ref\">historical model</span></a> ，因此没有任何自定义属性，方法或管理器。你应该只能依赖 <code class=\"docutils literal notranslate\">_meta</code> 。</p>\n<p>这个方法也可以用于确定给定数据库上模型的可用性。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#django-admin-makemigrations\"><code class=\"xref std std-djadmin docutils literal notranslate\">makemigrations</code></a> 会在模型变动时创建迁移，但如果 <code class=\"docutils literal notranslate\">allow_migrate()</code> 返回 <code class=\"docutils literal notranslate\">False` ，任何针对 ``model_name</code> 的迁移操作会在运行 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">migrate</code></a> 的时候跳过。对于已经迁移过的模型，改变  <code class=\"docutils literal notranslate\">allow_migrate()</code> 的行为，可能会破坏主键，格外表或丢失的表。当 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/django-admin/#django-admin-makemigrations\"><code class=\"xref std std-djadmin docutils literal notranslate\">makemigrations</code></a> 核实迁移历史，它跳过不允许迁移的 app 的数据库。</p>\n</dd></dl>\n\n<p>路由不是必须提供所有这些方法——它也许省略它们中的一个或多个。如果某个方法被省略，Django会在执行相关检查时候，跳过这个路由。</p>\n<section id=\"hints\">\n<span id=\"topics-db-multi-db-hints\"></span><h4>提示<a class=\"heading-anchor\" href=\"#hints\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>通过数据库路由收到的提示可用来决定哪个数据库应该接收给定的请求。</p>\n<p>现在，将要提供的唯一的提示是 <code class=\"docutils literal notranslate\">instance</code>，这是一个与正在进行读写操作相关的对象实例。这可能是正在保存的实例，或是正在添加多对多关系的实例。在某些情况下，根本不会提供实例提示。路由检查是否存在实例提示，并确定提示是否应该用来改变路由行为。</p>\n</section>\n</section>\n<section id=\"using-routers\">\n<h3>使用路由<a class=\"heading-anchor\" href=\"#using-routers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>数据库路由器是使用 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-DATABASE_ROUTERS\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASE_ROUTERS</code></a> 设置来安装的。该设置定义了一个类名列表，每个类名都指定了一个应该被基本路由器（<code class=\"docutils literal notranslate\">django.db.router</code>）使用的路由器。</p>\n<p>基本路由器被用于分配数据库使用情况，用于 Django 的数据库操作。每当查询需要知道要使用哪个数据库时，它都会调用基本路由器，提供一个模型和一个提示（如果可用）。基本路由器依次尝试每个路由器类，直到一个返回数据库建议。如果没有路由器返回建议，基本路由器会尝试使用提示实例的当前 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/models/instances/#django.db.models.Model._state\" title=\"django.db.models.Model._state\"><code class=\"xref py py-attr docutils literal notranslate\">instance._state.db</code></a>。如果没有提供提示实例，或者 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/models/instances/#django.db.models.Model._state\" title=\"django.db.models.Model._state\"><code class=\"xref py py-attr docutils literal notranslate\">instance._state.db</code></a> 为 <code class=\"docutils literal notranslate\">None</code>，则基本路由器将分配到 <code class=\"docutils literal notranslate\">default</code> 数据库。</p>\n</section>\n<section id=\"an-example\">\n<h3>一个例子<a class=\"heading-anchor\" href=\"#an-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<aside class=\"admonition-example-purposes-only admonition\" role=\"note\">\n<p class=\"admonition-title\">仅供参考！</p>\n<p>这个例子旨在演示如何使用路由基础结构来改变数据库使用情况。它有意忽略一些复杂的问题，为了演示如何使用路由。</p>\n<p>如果 <code class=\"docutils literal notranslate\">myapp</code> 中的任何模型包含与其他数据库之外的模型的关系，那么这个例子将无法运行。<a class=\"reference internal\" href=\"#no-cross-database-relations\"><span class=\"std std-ref\">Cross-database relationships</span></a> 介绍了 Django 目前无法解决的引用完整性问题。</p>\n<p>主/副（一些数据库成为主/从）配置描述是有点问题的-它不提供任何处理复制滞后的解决方案（比如，由于写入传播到复制副本需要时间，导致查询不一致）。它也没有考虑事务与数据库利用策略的交互。</p>\n</aside>\n<p>所以-这在实践中意味着什么？我们考虑一下其他简单配置。它有一些数据库：一个 <code class=\"docutils literal notranslate\">auth</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>DATABASES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{},</span>\n    <span class=\"s2\">&quot;auth_db&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;auth_db_name&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;swordfish&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"s2\">&quot;primary&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;primary_name&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;spam&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"s2\">&quot;replica1&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;replica1_name&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;eggs&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"s2\">&quot;replica2&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;replica2_name&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;ENGINE&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.db.backends.mysql&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;USER&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mysql_user&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;PASSWORD&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;bacon&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>现在需要处理路由。首先需要一个将 <code class=\"docutils literal notranslate\">auth</code> 和 <code class=\"docutils literal notranslate\">contenttypes</code> app 的查询发送到 <code class=\"docutils literal notranslate\">auth_db</code> 的路由(<code class=\"docutils literal notranslate\">auth</code> 模型已经关联了 <code class=\"docutils literal notranslate\">ContentType</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\">class</span> <span class=\"nc\">AuthRouter</span><span class=\"p\">:</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A router to control all database operations on models in the</span>\n<span class=\"sd\">    auth and contenttypes applications.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    route_app_labels <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;auth&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;contenttypes&quot;</span><span class=\"p\">}</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">db_for_read</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> model<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Attempts to read auth and contenttypes models go to auth_db.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> model<span class=\"o\">.</span>_meta<span class=\"o\">.</span>app_label <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>route_app_labels<span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"s2\">&quot;auth_db&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">db_for_write</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> model<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Attempts to write auth and contenttypes models go to auth_db.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> model<span class=\"o\">.</span>_meta<span class=\"o\">.</span>app_label <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>route_app_labels<span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"s2\">&quot;auth_db&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">allow_relation</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> obj1<span class=\"p\">,</span> obj2<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Allow relations if a model in the auth or contenttypes apps is</span>\n<span class=\"sd\">        involved.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span>\n            obj1<span class=\"o\">.</span>_meta<span class=\"o\">.</span>app_label <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>route_app_labels\n            <span class=\"ow\">or</span> obj2<span class=\"o\">.</span>_meta<span class=\"o\">.</span>app_label <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>route_app_labels\n        <span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"kc\">True</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">allow_migrate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db<span class=\"p\">,</span> app_label<span class=\"p\">,</span> model_name<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Make sure the auth and contenttypes apps only appear in the</span>\n<span class=\"sd\">        &#39;auth_db&#39; database.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> app_label <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span>route_app_labels<span class=\"p\">:</span>\n            <span class=\"k\">return</span> db <span class=\"o\">==</span> <span class=\"s2\">&quot;auth_db&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</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=\"nn\">random</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">PrimaryReplicaRouter</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span> <span class=\"nf\">db_for_read</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> model<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Reads go to a randomly-chosen replica.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> random<span class=\"o\">.</span>choice<span class=\"p\">([</span><span class=\"s2\">&quot;replica1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;replica2&quot;</span><span class=\"p\">])</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">db_for_write</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> model<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Writes always go to primary.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;primary&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">allow_relation</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> obj1<span class=\"p\">,</span> obj2<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Relations between objects are allowed if both objects are</span>\n<span class=\"sd\">        in the primary/replica pool.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        db_set <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;primary&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;replica1&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;replica2&quot;</span><span class=\"p\">}</span>\n        <span class=\"k\">if</span> obj1<span class=\"o\">.</span>_state<span class=\"o\">.</span>db <span class=\"ow\">in</span> db_set <span class=\"ow\">and</span> obj2<span class=\"o\">.</span>_state<span class=\"o\">.</span>db <span class=\"ow\">in</span> db_set<span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">True</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">allow_migrate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db<span class=\"p\">,</span> app_label<span class=\"p\">,</span> model_name<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        All non-auth models end up in this pool.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>最后，在配置文件中，我们添加下面的代码（用定义路由器的模块的实际 Python 路径替换 <code class=\"docutils literal notranslate\">path.to.</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>DATABASE_ROUTERS <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;path.to.AuthRouter&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;path.to.PrimaryReplicaRouter&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>处理路由的顺序非常重要。路由将按照 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-DATABASE_ROUTERS\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASE_ROUTERS</code></a> 里设置的顺序查询。在这个例子里， <code class=\"docutils literal notranslate\">AuthRouter</code> 将在 <code class=\"docutils literal notranslate\">PrimaryReplicaRouter</code> 前处理，因此，在做出其他决定之前，先处理与 <code class=\"docutils literal notranslate\">auth</code> 相关的模型。如果 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-DATABASE_ROUTERS\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASE_ROUTERS</code></a> 设置在其他顺序里列出两个路由，<code class=\"docutils literal notranslate\">PrimaryReplicaRouter.allow_migrate()</code> 将首先处理。PrimaryReplicaRouter 实现的特性意味着所有模型可用于所有数据库。</p>\n<p>在这个设置安装并按照 <a class=\"reference internal\" href=\"#synchronizing-multiple-databases\"><span class=\"std std-ref\">同步数据库</span></a> 同步了所有数据库之后，让我们运行一些 Django 代码：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># This retrieval will be performed on the &#39;auth_db&#39; database</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>fred <span class=\"o\">=</span> User<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>username<span class=\"o\">=</span><span class=\"s2\">&quot;fred&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>fred<span class=\"o\">.</span>first_name <span class=\"o\">=</span> <span class=\"s2\">&quot;Frederick&quot;</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># This save will also be directed to &#39;auth_db&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>fred<span class=\"o\">.</span>save<span class=\"p\">()</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># These retrieval will be randomly allocated to a replica database</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>dna <span class=\"o\">=</span> Person<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Douglas Adams&quot;</span><span class=\"p\">)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># A new object has no database allocation when created</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>mh <span class=\"o\">=</span> Book<span class=\"p\">(</span>title<span class=\"o\">=</span><span class=\"s2\">&quot;Mostly Harmless&quot;</span><span class=\"p\">)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># This assignment will consult the router, and set mh onto</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># the same database as the author object</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>mh<span class=\"o\">.</span>author <span class=\"o\">=</span> dna\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># This save will force the &#39;mh&#39; instance onto the primary database...</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>mh<span class=\"o\">.</span>save<span class=\"p\">()</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># ... but if we re-retrieve the object, it will come back on a replica</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>mh <span class=\"o\">=</span> Book<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>title<span class=\"o\">=</span><span class=\"s2\">&quot;Mostly Harmless&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这个例子定义了一个路由来处理与来自 <code class=\"docutils literal notranslate\">auth</code> 应用的模型交互，其他路由处理与所以其他应用的交互。如果 <code class=\"docutils literal notranslate\">default</code> 为空，并且不想定义一个全能数据库来处理所有未指定的应用，那么路由必须在迁移之前处理 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 的所有应用名。查看 <a class=\"reference internal\" href=\"#contrib-app-multiple-databases\"><span class=\"std std-ref\">contrib应用程序的行为</span></a> 来了解 contrib 应用必须在一个数据库的信息。</p>\n</section>\n</section>\n<section id=\"manually-selecting-a-database\">\n<h2>手动选择数据库<a class=\"heading-anchor\" href=\"#manually-selecting-a-database\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django也提供允许在代码中完全控制数据库的API。手工指定数据库分配将优先于路由分配的数据库。</p>\n<section id=\"manually-selecting-a-database-for-a-queryset\">\n<h3>手动为查询集选择数据库<a class=\"heading-anchor\" href=\"#manually-selecting-a-database-for-a-queryset\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>你可以在查询集链的任一点为查询集选择数据库。调用查询集上的 <code class=\"docutils literal notranslate\">using()</code> 就可以获取使用指定数据库的其他查询集。</p>\n<p><code class=\"docutils literal notranslate\">using()</code> 接受一个参数：你想在哪个数据库上运行查询的别名。例如：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># This will run on the &#39;default&#39; database.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>all<span class=\"p\">()</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># So will this.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>using<span class=\"p\">(</span><span class=\"s2\">&quot;default&quot;</span><span class=\"p\">)</span>\n\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># This will run on the &#39;other&#39; database.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>Author<span class=\"o\">.</span>objects<span class=\"o\">.</span>using<span class=\"p\">(</span><span class=\"s2\">&quot;other&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"selecting-a-database-for-save\">\n<h3>为保存选择数据库<a class=\"heading-anchor\" href=\"#selecting-a-database-for-save\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>使用 <code class=\"docutils literal notranslate\">using</code> 关键字来 <code class=\"docutils literal notranslate\">Model.save()</code> 到指定的数据保存的数据库。</p>\n<p>例如，要将对象保存到 <code class=\"docutils literal notranslate\">legacy_users</code> 数据库，你可以这样做：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>my_object<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;legacy_users&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你没有指定 <code class=\"docutils literal notranslate\">using</code>，<code class=\"docutils literal notranslate\">save()</code> 方法将保存到路由的默认数据库分配。</p>\n<section id=\"moving-an-object-from-one-database-to-another\">\n<h4>将对象从一个数据库移动到另一个<a class=\"heading-anchor\" href=\"#moving-an-object-from-one-database-to-another\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>如果已经保存实例到数据库，它可能使用 <code class=\"docutils literal notranslate\">save(using=...)</code> 作为迁移实例到新数据库的方法。然而，如果没有使用适合的步骤，这可能会产生意想不到的结果。</p>\n<p>考虑以下示例：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>p <span class=\"o\">=</span> Person<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Fred&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;first&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># (statement 1)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;second&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># (statement 2)</span>\n</code></pre></div>\n<p>在语句1，新的 <code class=\"docutils literal notranslate\">Person</code> 对象保存在 <code class=\"docutils literal notranslate\">first</code> 数据库。这一次，<code class=\"docutils literal notranslate\">p</code> 没有主键，因此 Django 发出了一个SQL <code class=\"docutils literal notranslate\">INSERT</code> 语句。这会创建主键，并且 Django 分配那个主键到 <code class=\"docutils literal notranslate\">p</code>。</p>\n<p>在语句2中进行保存时，<code class=\"docutils literal notranslate\">p</code> 也有主键值，Django 将试图在新的数据库上使用主键。如果主键值未在 <code class=\"docutils literal notranslate\">second</code> 数据库中使用，那么将不会有任何问题——对象将被拷贝到新数据库。</p>\n<p>然而，如果 <code class=\"docutils literal notranslate\">p</code> 的主键已经在 <code class=\"docutils literal notranslate\">second</code> 数据库上使用，那么当保存 <code class=\"docutils literal notranslate\">p</code> 的时候， <code class=\"docutils literal notranslate\">second</code> 数据库中存在的对象将被覆盖。</p>\n<p>你可以以两种方式避免这种情况。首先，你可以清除实例的主键。如果一个对象没有主键，Django 会将其视为新对象，从而避免在 <code class=\"docutils literal notranslate\">second</code> 数据库上丢失任何数据：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>p <span class=\"o\">=</span> Person<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Fred&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;first&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>pk <span class=\"o\">=</span> <span class=\"kc\">None</span>  <span class=\"c1\"># Clear the primary key.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;second&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># Write a completely new object.</span>\n</code></pre></div>\n<p>第二个选项是使用 <code class=\"docutils literal notranslate\">save()</code> 的 <code class=\"docutils literal notranslate\">force_insert</code> 选项，以确保 Django 执行 SQL <code class=\"docutils literal notranslate\">INSERT</code>：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>p <span class=\"o\">=</span> Person<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Fred&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;first&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>p<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;second&quot;</span><span class=\"p\">,</span> force_insert<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这将确保 <code class=\"docutils literal notranslate\">Fred</code> 在两个数据库上拥有同一个主键。当试着在 <code class=\"docutils literal notranslate\">second</code> 上保存时，如果主键已经保存，那么将会引发一个错误。</p>\n</section>\n</section>\n<section id=\"selecting-a-database-to-delete-from\">\n<h3>选择要删除的数据库<a class=\"heading-anchor\" href=\"#selecting-a-database-to-delete-from\"><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=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>u <span class=\"o\">=</span> User<span class=\"o\">.</span>objects<span class=\"o\">.</span>using<span class=\"p\">(</span><span class=\"s2\">&quot;legacy_users&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span>get<span class=\"p\">(</span>username<span class=\"o\">=</span><span class=\"s2\">&quot;fred&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>u<span class=\"o\">.</span>delete<span class=\"p\">()</span>  <span class=\"c1\"># will delete from the `legacy_users` database</span>\n</code></pre></div>\n<p>指定将要删除模型的数据库，传递 <code class=\"docutils literal notranslate\">using</code> 关键字参数到 <code class=\"docutils literal notranslate\">Model.delete()</code> 方法。这个参数的工作方式与用关键字参数 <code class=\"docutils literal notranslate\">save()</code> 是一样的。</p>\n<p>例如，如果你要从 <code class=\"docutils literal notranslate\">legacy_users</code> 数据库迁移到 <code class=\"docutils literal notranslate\">new_users</code> 数据库的用户，你可以使用以下命令：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>user_obj<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;new_users&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>user_obj<span class=\"o\">.</span>delete<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"s2\">&quot;legacy_users&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"using-managers-with-multiple-databases\">\n<h3>使用多个数据库管理器<a class=\"heading-anchor\" href=\"#using-managers-with-multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在管理器上使用 <code class=\"docutils literal notranslate\">db_manager()</code> 方法来让管理员访问非默认数据库。</p>\n<p>比如，假设有一个自定义管理器方法来触发数据库——<code class=\"docutils literal notranslate\">User.objects.create_user()</code>。因为 <code class=\"docutils literal notranslate\">create_user()</code> 是一个管理器方法，不是 <code class=\"docutils literal notranslate\">QuerySet</code> 方法，你不能操作 <code class=\"docutils literal notranslate\">User.objects.using('new_users').create_user()</code> 。（<code class=\"docutils literal notranslate\">create_user()</code> 方法只适用 <code class=\"docutils literal notranslate\">User.objects</code> ，即管理器，而不是来自管理器上的 <code class=\"docutils literal notranslate\">QuerySet</code> 。）解决方案是使用 <code class=\"docutils literal notranslate\">db_manager()</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>User<span class=\"o\">.</span>objects<span class=\"o\">.</span>db_manager<span class=\"p\">(</span><span class=\"s2\">&quot;new_users&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span>create_user<span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">db_manager()</code> 返回绑定到指定数据库的管理器副本。</p>\n<section id=\"using-get-queryset-with-multiple-databases\">\n<h4>将 <code class=\"docutils literal notranslate\">get_queryset()</code> 和多个数据库使用<a class=\"heading-anchor\" href=\"#using-get-queryset-with-multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>如果在管理器上覆盖了 <code class=\"docutils literal notranslate\">get_queryset()</code> ，请确保在父类上调用这个方法（使用 <code class=\"docutils literal notranslate\">super()</code> ）或者在管理器（包含使用的数据库的名字）上适当处理 <code class=\"docutils literal notranslate\">_db</code> 属性。</p>\n<p>比如，如果你想从 <code class=\"docutils literal notranslate\">get_queryset</code> 方法返回自定义的 <code class=\"docutils literal notranslate\">QuerySet</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\">class</span> <span class=\"nc\">MyManager</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Manager<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        qs <span class=\"o\">=</span> CustomQuerySet<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>model<span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span>_db <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            qs <span class=\"o\">=</span> qs<span class=\"o\">.</span>using<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>_db<span class=\"p\">)</span>\n        <span class=\"k\">return</span> qs\n</code></pre></div>\n</section>\n</section>\n</section>\n<section id=\"exposing-multiple-databases-in-django-s-admin-interface\">\n<h2>在Django管理界面中使用多数据库<a class=\"heading-anchor\" href=\"#exposing-multiple-databases-in-django-s-admin-interface\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django的管理后台对多数据库没有明显的支持。如果要为路由指定的数据库以外的数据库提供模型的管理界面，你需要编写自定义的 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\">ModelAdmin</code></a> 类，这个类将指示管理后台使用指定数据库的内容。</p>\n<p><code class=\"docutils literal notranslate\">ModelAdmin</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\">class</span> <span class=\"nc\">MultiDBModelAdmin</span><span class=\"p\">(</span>admin<span class=\"o\">.</span>ModelAdmin<span class=\"p\">):</span>\n    <span class=\"c1\"># A handy constant for the name of the alternate database.</span>\n    using <span class=\"o\">=</span> <span class=\"s2\">&quot;other&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">save_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> obj<span class=\"p\">,</span> form<span class=\"p\">,</span> change<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to save objects to the &#39;other&#39; database.</span>\n        obj<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">delete_model</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> obj<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to delete objects from the &#39;other&#39; database</span>\n        obj<span class=\"o\">.</span>delete<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to look for objects on the &#39;other&#39; database.</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>get_queryset<span class=\"p\">(</span>request<span class=\"p\">)</span><span class=\"o\">.</span>using<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">formfield_for_foreignkey</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to populate ForeignKey widgets using a query</span>\n        <span class=\"c1\"># on the &#39;other&#39; database.</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>formfield_for_foreignkey<span class=\"p\">(</span>\n            db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs\n        <span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">formfield_for_manytomany</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to populate ManyToMany widgets using a query</span>\n        <span class=\"c1\"># on the &#39;other&#39; database.</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>formfield_for_manytomany<span class=\"p\">(</span>\n            db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs\n        <span class=\"p\">)</span>\n</code></pre></div>\n<p>此处提供的实现方法实现了多数据库策略，其中给定类型的所有对象保存在指定数据库上（比如所有 <code class=\"docutils literal notranslate\">User</code> 对象在 <code class=\"docutils literal notranslate\">other</code> 数据库中）。如果对多数据的使用很复杂，那么``ModelAdmin`` 将需要映射策略。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin\" title=\"django.contrib.admin.InlineModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\">InlineModelAdmin</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=\"k\">class</span> <span class=\"nc\">MultiDBTabularInline</span><span class=\"p\">(</span>admin<span class=\"o\">.</span>TabularInline<span class=\"p\">):</span>\n    using <span class=\"o\">=</span> <span class=\"s2\">&quot;other&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to look for inline objects on the &#39;other&#39; database.</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>get_queryset<span class=\"p\">(</span>request<span class=\"p\">)</span><span class=\"o\">.</span>using<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">formfield_for_foreignkey</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to populate ForeignKey widgets using a query</span>\n        <span class=\"c1\"># on the &#39;other&#39; database.</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>formfield_for_foreignkey<span class=\"p\">(</span>\n            db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs\n        <span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">formfield_for_manytomany</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        <span class=\"c1\"># Tell Django to populate ManyToMany widgets using a query</span>\n        <span class=\"c1\"># on the &#39;other&#39; database.</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>formfield_for_manytomany<span class=\"p\">(</span>\n            db_field<span class=\"p\">,</span> request<span class=\"p\">,</span> using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>using<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs\n        <span class=\"p\">)</span>\n</code></pre></div>\n<p>一旦编写了模型管理定义，就可以在任何 <code class=\"docutils literal notranslate\">Admin</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=\"nn\">django.contrib</span> <span class=\"kn\">import</span> admin\n\n\n<span class=\"c1\"># Specialize the multi-db admin objects for use with specific models.</span>\n<span class=\"k\">class</span> <span class=\"nc\">BookInline</span><span class=\"p\">(</span>MultiDBTabularInline<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Book\n\n\n<span class=\"k\">class</span> <span class=\"nc\">PublisherAdmin</span><span class=\"p\">(</span>MultiDBModelAdmin<span class=\"p\">):</span>\n    inlines <span class=\"o\">=</span> <span class=\"p\">[</span>BookInline<span class=\"p\">]</span>\n\n\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>register<span class=\"p\">(</span>Author<span class=\"p\">,</span> MultiDBModelAdmin<span class=\"p\">)</span>\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>register<span class=\"p\">(</span>Publisher<span class=\"p\">,</span> PublisherAdmin<span class=\"p\">)</span>\n\nothersite <span class=\"o\">=</span> admin<span class=\"o\">.</span>AdminSite<span class=\"p\">(</span><span class=\"s2\">&quot;othersite&quot;</span><span class=\"p\">)</span>\nothersite<span class=\"o\">.</span>register<span class=\"p\">(</span>Publisher<span class=\"p\">,</span> MultiDBModelAdmin<span class=\"p\">)</span>\n</code></pre></div>\n<p>这个例子设置了两个管理长点。在第一个站点上，<code class=\"docutils literal notranslate\">Author</code> 和 <code class=\"docutils literal notranslate\">Publisher</code> 对象是显式的；<code class=\"docutils literal notranslate\">Publisher</code> 对象有一个表格行来显示出版者的书籍。第二个站点只显示出版者，不显示内嵌。</p>\n</section>\n<section id=\"using-raw-cursors-with-multiple-databases\">\n<h2>将原始游标用于多个数据库<a class=\"heading-anchor\" href=\"#using-raw-cursors-with-multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果正在使用不止一个数据库，可以使用 <code class=\"docutils literal notranslate\">django.db.connections</code> 来获得链接指定的数据库。<code class=\"docutils literal notranslate\">django.db.connections</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=\"nn\">django.db</span> <span class=\"kn\">import</span> connections\n\n<span class=\"k\">with</span> connections<span class=\"p\">[</span><span class=\"s2\">&quot;my_db_alias&quot;</span><span class=\"p\">]</span><span class=\"o\">.</span>cursor<span class=\"p\">()</span> <span class=\"k\">as</span> cursor<span class=\"p\">:</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n</section>\n<section id=\"limitations-of-multiple-databases\">\n<h2>多数据库的局限性<a class=\"heading-anchor\" href=\"#limitations-of-multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"cross-database-relations\">\n<span id=\"no-cross-database-relations\"></span><h3>跨数据库关系<a class=\"heading-anchor\" href=\"#cross-database-relations\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django 当前不提供对跨多数据库的外键或多对多关系任何支持。如果已经使用路由来分隔模型到不同数据库，那么通过这些模型来定义的任何外键和多对多关系必须在单一数据库内。</p>\n<p>这是因为参照完整性。为了维护两个对象之间的关系，Djagno 需要知道这个相关对象的外键是否是合法的。如果外键被保存在单独的数据库上，则无法轻松评价外键的合法性。</p>\n<p>如果你正在使用 Postgres，Oracle，或支持 InnoDB 的 MySQL，这是在数据库完整性级别上强制执行的——数据库级别的键约束防止创建无法验证的关系。</p>\n<p>然而，如果你正在使用 SQLite 或支持 MyISAM 表的MySQL，这就不会强制参照完整性；因此，你可以伪造跨数据库的外键。尽管 Django 并没有正式支持这个设置。</p>\n</section>\n<section id=\"behavior-of-contrib-apps\">\n<span id=\"contrib-app-multiple-databases\"></span><h3>contrib应用程序的行为<a class=\"heading-anchor\" href=\"#behavior-of-contrib-apps\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>一些贡献应用包括模型，一些应用依赖于其他应用。 由于跨数据库关系是不可能的，因此这会对如何跨数据库拆分这些模型产生一些限制：</p>\n<ul class=\"simple\">\n<li><p>在给定合适的路由器的情况下，<code class=\"docutils literal notranslate\">contenttypes.ContentType</code>，<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>sessions.Session``和``sites.Site``中的每一个都可以存储在任何数据库中。</p></li>\n<li><p><code class=\"docutils literal notranslate\">auth``模型 - ``User</code>，<code class=\"docutils literal notranslate\">Group``和``Permission</code> - 链接在一起并链接到``ContentType``，因此它们必须与``ContentType存储在同一个数据库中``。</p></li>\n<li><p><code class=\"docutils literal notranslate\">admin``依赖于``auth</code>，所以它的模型必须和``auth``在同一个数据库中。</p></li>\n<li><p><code class=\"docutils literal notranslate\">flatpages``和``redirects``依赖于``sites</code>，所以他们的模型必须和``sites``在同一个数据库中。</p></li>\n</ul>\n<p>此外，一些对象在以下之后自动创建：djadmin：<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>migrate`创建一个表以将它们保存在数据库中：</p>\n<ul class=\"simple\">\n<li><p>默认的``Site``，</p></li>\n<li><p>每个模型的``ContentType`` （包括那些未存储在该数据库中的模型），</p></li>\n<li><p>每个模型的``Permission``s（包括那些未存储在该数据库中的模型）。</p></li>\n</ul>\n<p>对于具有多个数据库的常见设置，将这些对象放在多个数据库中是没有用的。 常见设置包括主/副本和连接到外部数据库。 因此，建议编写一个：ref:database router，它允许将这三个模型同步到一个数据库。 对于不需要在多个数据库中使用其表的contrib和第三方应用程序，请使用相同的方法。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>如果要将内容类型同步到多个数据库，请注意它们的主键可能在数据库之间不匹配。这可能导致数据损坏或数据丢失。</p>\n</aside>\n</section>\n</section>","rootId":"multiple-databases","toc":[{"title":"定义数据库","anchor":"defining-your-databases","children":[]},{"title":"同步数据库","anchor":"synchronizing-your-databases","children":[{"title":"使用其他管理命令","anchor":"using-other-management-commands","children":[]}]},{"title":"自动数据库路由","anchor":"automatic-database-routing","children":[{"title":"数据库路由","anchor":"database-routers","children":[{"title":"提示","anchor":"hints","children":[]}]},{"title":"使用路由","anchor":"using-routers","children":[]},{"title":"一个例子","anchor":"an-example","children":[]}]},{"title":"手动选择数据库","anchor":"manually-selecting-a-database","children":[{"title":"手动为查询集选择数据库","anchor":"manually-selecting-a-database-for-a-queryset","children":[]},{"title":"为保存选择数据库","anchor":"selecting-a-database-for-save","children":[{"title":"将对象从一个数据库移动到另一个","anchor":"moving-an-object-from-one-database-to-another","children":[]}]},{"title":"选择要删除的数据库","anchor":"selecting-a-database-to-delete-from","children":[]},{"title":"使用多个数据库管理器","anchor":"using-managers-with-multiple-databases","children":[{"title":"将 get_queryset() 和多个数据库使用","anchor":"using-get-queryset-with-multiple-databases","children":[]}]}]},{"title":"在Django管理界面中使用多数据库","anchor":"exposing-multiple-databases-in-django-s-admin-interface","children":[]},{"title":"将原始游标用于多个数据库","anchor":"using-raw-cursors-with-multiple-databases","children":[]},{"title":"多数据库的局限性","anchor":"limitations-of-multiple-databases","children":[{"title":"跨数据库关系","anchor":"cross-database-relations","children":[]},{"title":"contrib应用程序的行为","anchor":"behavior-of-contrib-apps","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/4.2/topics/"},{"docname":"topics/db/index","title":"模型和数据库","url":"/zh-hans/4.2/topics/db/"}],"prev":{"docname":"topics/db/transactions","title":"数据库事务","url":"/zh-hans/4.2/topics/db/transactions/"},"next":{"docname":"topics/db/tablespaces","title":"表空间（Tablespaces）","url":"/zh-hans/4.2/topics/db/tablespaces/"},"formats":{"html":"/zh-hans/4.2/topics/db/multi-db/","markdown":"/zh-hans/4.2/topics/db/multi-db.md","json":"/zh-hans/4.2/topics/db/multi-db.json"},"source":"https://github.com/django/django/blob/stable/4.2.x/docs/topics/db/multi-db.txt","official":"https://docs.djangoproject.com/zh-hans/4.2/topics/db/multi-db/","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","it","pt-br","ko","es","el","pl"]}