{"title":"序列化 Django 对象","version":"5.0","locale":"zh-hans","docname":"topics/serialization","url":"/zh-hans/5.0/topics/serialization/","canonical":"https://djangodocs.dev/zh-hans/5.0/topics/serialization/","summary":"Django 的序列化框架提供了一种将 Django 模型“翻译”为其他格式的机制。通常，这些其他格式将基于文本，并用于在网络上发送 Django 数据，但是序列化程序可以处理任何格式（无论是否基于文本）。 See also 如果你只是想将表中的某些数据转换为序列化形式，你可以使用 dumpdata 管理命令。 序列化数据…","html":"<h1>序列化 Django 对象<a class=\"heading-anchor\" href=\"#serializing-django-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 的序列化框架提供了一种将 Django 模型“翻译”为其他格式的机制。通常，这些其他格式将基于文本，并用于在网络上发送 Django 数据，但是序列化程序可以处理任何格式（无论是否基于文本）。</p>\n<aside class=\"admonition admonition-seealso\">\n<p class=\"admonition-title\">See also</p>\n<p>如果你只是想将表中的某些数据转换为序列化形式，你可以使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#django-admin-dumpdata\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">dumpdata</span></code></a> 管理命令。</p>\n</aside>\n<section id=\"serializing-data\">\n<h2>序列化数据<a class=\"heading-anchor\" href=\"#serializing-data\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\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.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">serializers</span>\n\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">SomeModel</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">())</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">serialize</span></code> 函数的参数是数据序列化的目标格式 （查看 <a class=\"reference internal\" href=\"#id2\">序列化格式</a>）和用来序列化的 <a class=\"reference internal\" href=\"/zh-hans/5.0/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>。（实际上，第二个参数可以是任何生成 Django 模型实例的迭代器，但它几乎总是一个QuerySet）。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.core.serializers.get_serializer\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">django.core.serializers.</span></span><span class=\"sig-name descname\"><span class=\"pre\">get_serializer</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">format</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.serializers.get_serializer\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>你也可以直接使用序列化器对象：</p>\n<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\">XMLSerializer</span> <span class=\"o\">=</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">get_serializer</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">xml_serializer</span> <span class=\"o\">=</span> <span class=\"n\">XMLSerializer</span><span class=\"p\">()</span>\n<span class=\"n\">xml_serializer</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"n\">queryset</span><span class=\"p\">)</span>\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">xml_serializer</span><span class=\"o\">.</span><span class=\"n\">getvalue</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>如果要将数据直接序列化到类似文件的对象（包括 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</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=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s2\">&quot;file.xml&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;w&quot;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">out</span><span class=\"p\">:</span>\n    <span class=\"n\">xml_serializer</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"n\">SomeModel</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">(),</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">out</span><span class=\"p\">)</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>以未知 <a class=\"reference internal\" href=\"#serialization-formats\"><span class=\"std std-ref\">格式</span></a> 调用 <a class=\"reference internal\" href=\"#django.core.serializers.get_serializer\" title=\"django.core.serializers.get_serializer\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">get_serializer()</span></code></a> 将引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.core.serializers.SerializerDoesNotExist</span></code> 异常。</p>\n</aside>\n<section id=\"subset-of-fields\">\n<span id=\"id1\"></span><h3>字段子集<a class=\"heading-anchor\" href=\"#subset-of-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\">fields</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.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">serializers</span>\n\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">SomeModel</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">(),</span> <span class=\"n\">fields</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;size&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>在此示例中，将仅序列化每个模型的 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">size</span></code> 属性。主键总是序列化为结果输出中的 <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> 元素；它永远不会出现在 <code class=\"docutils literal notranslate\"><span class=\"pre\">fields</span></code> 部分。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>根据你的模型，你可能会发现无法反序列化一个仅序列化了其字段子集的模型。如果已序列化的对象未指定模型所需的所有字段，则反序列化器将无法保存反序列化的实例。</p>\n</aside>\n</section>\n<section id=\"inherited-models\">\n<h3>继承来的模型<a class=\"heading-anchor\" href=\"#inherited-models\"><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/5.0/topics/db/models/#abstract-base-classes\"><span class=\"std std-ref\">抽象基类</span></a> 定义的模型，那么你不必做任何特殊的事情来序列化该模型。对要序列化的一个（或多个）对象调用序列化程序，输出将是序列化对象的完整表示形式。</p>\n<p>但是，如果你有一个使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/topics/db/models/#multi-table-inheritance\"><span class=\"std std-ref\">多表继承</span></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=\"w\"> </span><span class=\"nc\">Place</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\">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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Restaurant</span><span class=\"p\">(</span><span class=\"n\">Place</span><span class=\"p\">):</span>\n    <span class=\"n\">serves_hot_dogs</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">BooleanField</span><span class=\"p\">(</span><span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你只序列化 Restaurant 模型：</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\">data</span> <span class=\"o\">=</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">Restaurant</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">())</span>\n</code></pre></div>\n<p>序列化输出上的字段将仅包含 <code class=\"docutils literal notranslate\"><span class=\"pre\">serves_hot_dogs</span></code> 属性。基类的 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> 属性将被忽略。</p>\n<p>为了完全序列化你的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Restaurant</span></code> 实例，你还需要将 <code class=\"docutils literal notranslate\"><span class=\"pre\">Place</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=\"n\">all_objects</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"o\">*</span><span class=\"n\">Restaurant</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">(),</span> <span class=\"o\">*</span><span class=\"n\">Place</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">()]</span>\n<span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">all_objects</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"deserializing-data\">\n<h2>反序列化数据<a class=\"heading-anchor\" href=\"#deserializing-data\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\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\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">deserialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">):</span>\n    <span class=\"n\">do_something_with</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如你所见，<code class=\"docutils literal notranslate\"><span class=\"pre\">deserialize</span></code> 函数与 <code class=\"docutils literal notranslate\"><span class=\"pre\">serialize</span></code> 函数采用相同的格式参数，字符串或数据流，并返回一个迭代器。</p>\n<p>不过，这里有点复杂。<code class=\"docutils literal notranslate\"><span class=\"pre\">deserialize</span></code> 迭代器返回的对象 <em>不是</em> 常规的 Django 对象。相反，它们是特殊的 <code class=\"docutils literal notranslate\"><span class=\"pre\">DeserializedObject</span></code> 实例，实例封装了一个已创建 -- 但未保存 -- 的对象和任何相关联的数据。</p>\n<p>调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">DeserializedObject.save()</span></code> 保存对象到数据库。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>如果序列化数据中的 <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> 属性不存在或为 null，则会将新实例保存到数据库中。</p>\n</aside>\n<p>这可以确保反序列化是一个非破坏性操作，即使序列化表示中的数据与数据库中当前的数据不匹配。通常，使用这些 <code class=\"docutils literal notranslate\"><span class=\"pre\">DeserializedObject</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\">for</span> <span class=\"n\">deserialized_object</span> <span class=\"ow\">in</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">deserialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">object_should_be_saved</span><span class=\"p\">(</span><span class=\"n\">deserialized_object</span><span class=\"p\">):</span>\n        <span class=\"n\">deserialized_object</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>换句话说，通常的用途是检查反序列化的对象，以确保它们“适合”保存。如果你信任数据源，则可以直接保存对象并继续前进。</p>\n<p>Django 对象本身可以被像 <code class=\"docutils literal notranslate\"><span class=\"pre\">deserialized_object.object</span></code> 一样检查。如果模型中不存在序列化字段，将引发 <code class=\"docutils literal notranslate\"><span class=\"pre\">DeserializationError</span></code> 错误，除非将 <code class=\"docutils literal notranslate\"><span class=\"pre\">ignorenonexistent</span></code> 参数为 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</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=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">deserialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">ignorenonexistent</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"serialization-formats\">\n<span id=\"id2\"></span><h2>序列化格式<a class=\"heading-anchor\" href=\"#serialization-formats\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 支持多种序列化格式，其中一些格式要求你安装第三方 Python 模块：</p>\n<div class=\"table-scroll\" role=\"region\" tabindex=\"0\" aria-label=\"Table\"><table class=\"docutils align-default\">\n<thead>\n<tr class=\"row-odd\"><th class=\"head\"><p>标识符</p></th>\n<th class=\"head\"><p>信息</p></th>\n</tr>\n</thead>\n<tbody>\n<tr class=\"row-even\"><td><p><code class=\"docutils literal notranslate\"><span class=\"pre\">xml</span></code></p></td>\n<td><p>序列化和反序列化为一种简单地 XML 方言。</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><code class=\"docutils literal notranslate\"><span class=\"pre\">json</span></code></p></td>\n<td><p>序列化和反序列化为 <a class=\"reference external\" href=\"https://json.org/\">JSON</a>。</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><code class=\"docutils literal notranslate\"><span class=\"pre\">jsonl</span></code></p></td>\n<td><p>序列化和反序列化为 <a class=\"reference external\" href=\"https://jsonlines.org/\">JSONL</a>。</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><code class=\"docutils literal notranslate\"><span class=\"pre\">yaml</span></code></p></td>\n<td><p>序列化为 YAML（YAML 不是标记语言）。此序列化器仅在 <a class=\"reference external\" href=\"https://pyyaml.org/\">PyYAML</a> 安装后可用。</p></td>\n</tr>\n</tbody>\n</table>\n</div>\n<section id=\"xml\">\n<h3>XML<a class=\"heading-anchor\" href=\"#xml\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>基本的 XML 序列化格式如下：</p>\n<div class=\"code-block\" data-language=\"xml\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">XML</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=\"XML code\"><code><span class=\"cp\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>\n<span class=\"nt\">&lt;django-objects</span><span class=\"w\"> </span><span class=\"na\">version=</span><span class=\"s\">&quot;1.0&quot;</span><span class=\"nt\">&gt;</span>\n<span class=\"w\">    </span><span class=\"nt\">&lt;object</span><span class=\"w\"> </span><span class=\"na\">pk=</span><span class=\"s\">&quot;123&quot;</span><span class=\"w\"> </span><span class=\"na\">model=</span><span class=\"s\">&quot;sessions.session&quot;</span><span class=\"nt\">&gt;</span>\n<span class=\"w\">        </span><span class=\"nt\">&lt;field</span><span class=\"w\"> </span><span class=\"na\">type=</span><span class=\"s\">&quot;DateTimeField&quot;</span><span class=\"w\"> </span><span class=\"na\">name=</span><span class=\"s\">&quot;expire_date&quot;</span><span class=\"nt\">&gt;</span>2013-01-16T08:16:59.844560+00:00<span class=\"nt\">&lt;/field&gt;</span>\n<span class=\"w\">        </span><span class=\"cm\">&lt;!-- ... --&gt;</span>\n<span class=\"w\">    </span><span class=\"nt\">&lt;/object&gt;</span>\n<span class=\"nt\">&lt;/django-objects&gt;</span>\n</code></pre></div>\n<p>序列化或反序列化的整个对象集合由一个包含多个 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;object&gt;</span></code> - 元素的 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;django-objects&gt;</span></code> - 标签标识。每个这样的对象都有两个属性：“pk”和“model”，后者由用点号分隔的 app 名称（“sessions”）和模型的小写名称（“session”）来代替。</p>\n<p>对象的每个字段都序列化为一个具有“type”和“name”的 <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;field&gt;</span></code>- 元素 。元素的文本内容表示应该存储的值。</p>\n<p>外键和其他关系字段的处理略有不同：</p>\n<div class=\"code-block\" data-language=\"xml\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">XML</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=\"XML code\"><code><span class=\"nt\">&lt;object</span><span class=\"w\"> </span><span class=\"na\">pk=</span><span class=\"s\">&quot;27&quot;</span><span class=\"w\"> </span><span class=\"na\">model=</span><span class=\"s\">&quot;auth.permission&quot;</span><span class=\"nt\">&gt;</span>\n<span class=\"w\">    </span><span class=\"cm\">&lt;!-- ... --&gt;</span>\n<span class=\"w\">    </span><span class=\"nt\">&lt;field</span><span class=\"w\"> </span><span class=\"na\">to=</span><span class=\"s\">&quot;contenttypes.contenttype&quot;</span><span class=\"w\"> </span><span class=\"na\">name=</span><span class=\"s\">&quot;content_type&quot;</span><span class=\"w\"> </span><span class=\"na\">rel=</span><span class=\"s\">&quot;ManyToOneRel&quot;</span><span class=\"nt\">&gt;</span>9<span class=\"nt\">&lt;/field&gt;</span>\n<span class=\"w\">    </span><span class=\"cm\">&lt;!-- ... --&gt;</span>\n<span class=\"nt\">&lt;/object&gt;</span>\n</code></pre></div>\n<p>在本例中，我们指定具有 PK 27 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">auth.Permission</span></code> 对象有一个指向 PK 9 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">contenttypes.ContentType</span></code> 实例的外键。</p>\n<p>ManyToMany 关系是针对绑定它们的模型导出的。例如，<code class=\"docutils literal notranslate\"><span class=\"pre\">auth.User</span></code> 模型与 <code class=\"docutils literal notranslate\"><span class=\"pre\">auth.Permission</span></code> 模型有这样的关系：</p>\n<div class=\"code-block\" data-language=\"xml\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">XML</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=\"XML code\"><code><span class=\"nt\">&lt;object</span><span class=\"w\"> </span><span class=\"na\">pk=</span><span class=\"s\">&quot;1&quot;</span><span class=\"w\"> </span><span class=\"na\">model=</span><span class=\"s\">&quot;auth.user&quot;</span><span class=\"nt\">&gt;</span>\n<span class=\"w\">    </span><span class=\"cm\">&lt;!-- ... --&gt;</span>\n<span class=\"w\">    </span><span class=\"nt\">&lt;field</span><span class=\"w\"> </span><span class=\"na\">to=</span><span class=\"s\">&quot;auth.permission&quot;</span><span class=\"w\"> </span><span class=\"na\">name=</span><span class=\"s\">&quot;user_permissions&quot;</span><span class=\"w\"> </span><span class=\"na\">rel=</span><span class=\"s\">&quot;ManyToManyRel&quot;</span><span class=\"nt\">&gt;</span>\n<span class=\"w\">        </span><span class=\"nt\">&lt;object</span><span class=\"w\"> </span><span class=\"na\">pk=</span><span class=\"s\">&quot;46&quot;</span><span class=\"nt\">&gt;&lt;/object&gt;</span>\n<span class=\"w\">        </span><span class=\"nt\">&lt;object</span><span class=\"w\"> </span><span class=\"na\">pk=</span><span class=\"s\">&quot;47&quot;</span><span class=\"nt\">&gt;&lt;/object&gt;</span>\n<span class=\"w\">    </span><span class=\"nt\">&lt;/field&gt;</span>\n<span class=\"nt\">&lt;/object&gt;</span>\n</code></pre></div>\n<p>此示例将给定用户与 PK 46 和 47 的权限模型链接起来。</p>\n<aside class=\"admonition-control-characters admonition\">\n<p class=\"admonition-title\">控制字符</p>\n<p>如果要序列化的内容包含 XML 1.0 标准不接受的控制字符，则序列化将失败，并出现 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#ValueError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ValueError</span></code></a> 异常。另请阅读 W3C 对 <a class=\"reference external\" href=\"https://www.w3.org/International/questions/qa-controls\">HTML, XHTML, XML and Control Codes</a> 的解释。</p>\n</aside>\n</section>\n<section id=\"serialization-formats-json\">\n<span id=\"id3\"></span><h3>JSON<a class=\"heading-anchor\" href=\"#serialization-formats-json\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当与之前相同的示例数据保持不变时，它将按以下方式序列化为 JSON：</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=\"p\">[</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;4b678b301dfd8a4e0dad910de3ae245b&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;sessions.session&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;expire_date&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;2013-01-16T08:16:59.844Z&quot;</span><span class=\"p\">,</span>\n            <span class=\"c1\"># ...</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>这里的格式比 XML 简单一些。整个集合只是表示为一个数组，对象由具有三个属性的 JSON 对象表示：“pk”，“model”和“fields”。“fields”又是一个对象，其中分别包含每个字段的名称和值作为属性和属性值。</p>\n<p>外键将链接对象的 PK 作为属性值。多对多关系对于定义它们的模型进行了序列化，并表示为 PK 列表。</p>\n<p>请注意，并非所有的Django输出都可以不经修改地传递到 <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#module-json\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">json</span></code></a>。例如，如果要序列化对象中的某个自定义类型，则必须为其编写一个自定义 <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#module-json\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">json</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=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.serializers.json</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">DjangoJSONEncoder</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">LazyEncoder</span><span class=\"p\">(</span><span class=\"n\">DjangoJSONEncoder</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">default</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">,</span> <span class=\"n\">YourCustomType</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">default</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>你可以将 <code class=\"docutils literal notranslate\"><span class=\"pre\">cls=LazyEncoder</span></code> 传入 <code class=\"docutils literal notranslate\"><span class=\"pre\">serializers.serialize()</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.core.serializers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">serialize</span>\n\n<span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;json&quot;</span><span class=\"p\">,</span> <span class=\"n\">SomeModel</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">(),</span> <span class=\"bp\">cls</span><span class=\"o\">=</span><span class=\"n\">LazyEncoder</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>还要注意 GeoDjango 提供了一个 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/contrib/gis/serializers/\"><span class=\"doc\">定制的 GeoJSON 序列化器</span></a>.</p>\n<section id=\"djangojsonencoder\">\n<h4><code class=\"docutils literal notranslate\"><span class=\"pre\">DjangoJSONEncoder</span></code><a class=\"heading-anchor\" href=\"#djangojsonencoder\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.core.serializers.json.DjangoJSONEncoder\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">django.core.serializers.json.</span></span><span class=\"sig-name descname\"><span class=\"pre\">DjangoJSONEncoder</span></span><a class=\"heading-anchor\" href=\"#django.core.serializers.json.DjangoJSONEncoder\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>JSON 序列化器使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">DjangoJSONEncoder</span></code> 进行编码。作为 <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#json.JSONEncoder\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">JSONEncoder</span></code></a> 的子类，它可以处理这些附加类型：</p>\n<dl class=\"simple\">\n<dt><a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.datetime\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">datetime</span></code></a></dt><dd><p>格式为 <code class=\"docutils literal notranslate\"><span class=\"pre\">YYYY-MM-DDTHH:mm:ss.sssZ</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">YYYY-MM-DDTHH:mm:ss.sss+HH:MM</span></code> 的字符串，如 <a class=\"reference external\" href=\"https://262.ecma-international.org/5.1/#sec-15.9.1.15\">ECMA-262</a> 中定义。</p>\n</dd>\n<dt><a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.date\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">date</span></code></a></dt><dd><p>格式为 <code class=\"docutils literal notranslate\"><span class=\"pre\">YYYY-MM-DD</span></code> 的字符串，如 <a class=\"reference external\" href=\"https://262.ecma-international.org/5.1/#sec-15.9.1.15\">ECMA-262</a> 中定义。</p>\n</dd>\n<dt><a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.time\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">time</span></code></a></dt><dd><p>格式为 <code class=\"docutils literal notranslate\"><span class=\"pre\">HH:MM:ss.sss</span></code> 的字符串，如 <a class=\"reference external\" href=\"https://262.ecma-international.org/5.1/#sec-15.9.1.15\">ECMA-262</a> 中定义。</p>\n</dd>\n<dt><a class=\"reference external\" href=\"https://docs.python.org/3/library/datetime.html#datetime.timedelta\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">timedelta</span></code></a></dt><dd><p>代表 ISO-8601 中定义的持续时间的字符串。例如，<code class=\"docutils literal notranslate\"><span class=\"pre\">timedelta(days=1,</span> <span class=\"pre\">hours=2,</span> <span class=\"pre\">seconds=3.4)</span></code> 代表 <code class=\"docutils literal notranslate\"><span class=\"pre\">'P1DT02H00M03.400000S'</span></code>。</p>\n</dd>\n<dt><a class=\"reference external\" href=\"https://docs.python.org/3/library/decimal.html#decimal.Decimal\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Decimal</span></code></a>，<code class=\"docutils literal notranslate\"><span class=\"pre\">Promise</span></code> （ <code class=\"docutils literal notranslate\"><span class=\"pre\">django.utils.functional.lazy()</span></code> 对象），<a class=\"reference external\" href=\"https://docs.python.org/3/library/uuid.html#uuid.UUID\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">UUID</span></code></a></dt><dd><p>对象的字符串表示形式。</p>\n</dd>\n</dl>\n</section>\n</section>\n<section id=\"serialization-formats-jsonl\">\n<span id=\"id4\"></span><h3>JSONL<a class=\"heading-anchor\" href=\"#serialization-formats-jsonl\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><em>JSONL</em> 代表 <em>JSON 行</em>。使用这种格式，对象之间由换行符分隔，每一行包含一个有效的 JSON 对象。JSONL 序列化的数据如下所示：</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=\"p\">{</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;4b678b301dfd8a4e0dad910de3ae245b&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;sessions.session&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"o\">...</span><span class=\"p\">}}</span>\n<span class=\"p\">{</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;88bea72c02274f3c9bf1cb2bb8cee4fc&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;sessions.session&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"o\">...</span><span class=\"p\">}}</span>\n<span class=\"p\">{</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;9cf0e26691b64147a67e2a9f06ad7a53&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;sessions.session&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"o\">...</span><span class=\"p\">}}</span>\n</code></pre></div>\n<p>JSONL 可以用于填充大型数据库，因为数据可以逐行处理，而不必一次性加载到内存中。</p>\n</section>\n<section id=\"yaml\">\n<h3>YAML<a class=\"heading-anchor\" href=\"#yaml\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>YAML 序列化看起来与 JSON 相似。对象列表被序列化为一个序列映射，其中包括 &quot;pk&quot;、&quot;model&quot; 和 &quot;fields&quot; 键。每个字段都是一个映射，键是字段的名称，值是字段的值：</p>\n<div class=\"code-block\" data-language=\"yaml\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">YAML</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=\"YAML code\"><code><span class=\"p p-Indicator\">-</span><span class=\"w\"> </span><span class=\"nt\">model</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"l l-Scalar l-Scalar-Plain\">sessions.session</span>\n<span class=\"w\">  </span><span class=\"nt\">pk</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"l l-Scalar l-Scalar-Plain\">4b678b301dfd8a4e0dad910de3ae245b</span>\n<span class=\"w\">  </span><span class=\"nt\">fields</span><span class=\"p\">:</span>\n<span class=\"w\">    </span><span class=\"nt\">expire_date</span><span class=\"p\">:</span><span class=\"w\"> </span><span class=\"l l-Scalar l-Scalar-Plain\">2013-01-16 08:16:59.844560+00:00</span>\n</code></pre></div>\n<p>引用字段再次由 PK 或 PK 序列表示。</p>\n</section>\n</section>\n<section id=\"natural-keys\">\n<span id=\"topics-serialization-natural-keys\"></span><h2>自然键<a class=\"heading-anchor\" href=\"#natural-keys\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>外键和多对多关系的默认序列化策略是序列化在关系中对象主键的值。这种策略对大多数对象都有效，但在某些情况下可能会造成困难。</p>\n<p>考虑一个对象列表，这些对象的外键引用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/contrib/contenttypes/#django.contrib.contenttypes.models.ContentType\" title=\"django.contrib.contenttypes.models.ContentType\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ContentType</span></code></a>。如果要序列化引用内容类型的对象，那么首先需要有一种引用该内容类型的方法。由于 <code class=\"docutils literal notranslate\"><span class=\"pre\">ContentType</span></code> 对象是由 Django 在数据库同步过程中自动创建的，所以给定内容类型的主键不容易预测；这将取决于 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">migrate</span></code></a> 的执行方式和时间。对于自动生成对象的所有模型都是如此，特别是包括 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/contrib/auth/#django.contrib.auth.models.Permission\" title=\"django.contrib.auth.models.Permission\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Permission</span></code></a>，<a class=\"reference internal\" href=\"/zh-hans/5.0/ref/contrib/auth/#django.contrib.auth.models.Group\" title=\"django.contrib.auth.models.Group\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Group</span></code></a>，和 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a>。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>永远不要在辅助工具和其它序列化数据中包含自动生成的对象。偶尔，辅助工具中加载的主键可能与数据库中的相匹配而加载的辅助工具可能没有起到任何作用。更可能的情况是它们并不匹配，辅助工具将加载失败，并出现 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/exceptions/#django.db.IntegrityError\" title=\"django.db.IntegrityError\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">IntegrityError</span></code></a> 错误。</p>\n</aside>\n<p>还有一个便捷性的问题。整数 id 并不总是引用对象的最方便方式；有时，更自然的引用会有所帮助。</p>\n<p>正是由于这些原因 Django 提供了 <em>自然键</em>。自然键是一组值，可以用来唯一标识对象实例，而不使用主键值。</p>\n<section id=\"deserialization-of-natural-keys\">\n<h3>自然键反序列化<a class=\"heading-anchor\" href=\"#deserialization-of-natural-keys\"><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=\"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\">models</span>\n\n\n<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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n\n    <span class=\"n\">birthdate</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">constraints</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n            <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">UniqueConstraint</span><span class=\"p\">(</span>\n                <span class=\"n\">fields</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;first_name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;last_name&quot;</span><span class=\"p\">],</span>\n                <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;unique_first_last_name&quot;</span><span class=\"p\">,</span>\n            <span class=\"p\">),</span>\n        <span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Book</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\">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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">author</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Person</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>通常，序列化 <code class=\"docutils literal notranslate\"><span class=\"pre\">Book</span></code> 会使用一个整数来指代作者。例如，在 JSON 中，一个 Book 可以序列化为：</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=\"o\">...</span>\n<span class=\"p\">{</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;store.book&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Mostly Harmless&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;author&quot;</span><span class=\"p\">:</span> <span class=\"mi\">42</span><span class=\"p\">}}</span>\n<span class=\"o\">...</span>\n</code></pre></div>\n<p>这不是一个特别自然的方式来指代作者。它要求你知道作者的主键值；它还要求这个主键值是稳定的和可预测的。</p>\n<p>然而，如果我们向 Person 添加自然键处理，则辅助工具将变得更加人性化。要添加自然键处理， 你可以为 Person 定义一个有着 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_by_natural_key()</span></code> 方法的默认 Manager。对于 Person 来说，一个好的自然键可能是姓名：</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\">models</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">PersonManager</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Manager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_by_natural_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">first_name</span><span class=\"p\">,</span> <span class=\"n\">last_name</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">first_name</span><span class=\"o\">=</span><span class=\"n\">first_name</span><span class=\"p\">,</span> <span class=\"n\">last_name</span><span class=\"o\">=</span><span class=\"n\">last_name</span><span class=\"p\">)</span>\n\n\n<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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">birthdate</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"n\">PersonManager</span><span class=\"p\">()</span>\n\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">constraints</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n            <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">UniqueConstraint</span><span class=\"p\">(</span>\n                <span class=\"n\">fields</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;first_name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;last_name&quot;</span><span class=\"p\">],</span>\n                <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;unique_first_last_name&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\"><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=\"o\">...</span>\n<span class=\"p\">{</span>\n    <span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;store.book&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Mostly Harmless&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;author&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Douglas&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Adams&quot;</span><span class=\"p\">]},</span>\n<span class=\"p\">}</span>\n<span class=\"o\">...</span>\n</code></pre></div>\n<p>当你试图加载此序列化数据时，Django 将使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_by_natural_key()</span></code> 方法将 <code class=\"docutils literal notranslate\"><span class=\"pre\">[&quot;Douglas&quot;,</span> <span class=\"pre\">&quot;Adams&quot;]</span></code> 解析为 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 对象实际的主键。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>用于自然键的字段必须能够唯一标识一个对象。这通常意味着你的模型将对自然键的字段或字段（可以是单个字段上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">unique=True</span></code>，也可以是多个字段上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">UniqueConstraint</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">unique_together</span></code>）有一个唯一性约束。但是，唯一性并不一定要在数据库级别进行强制执行。如果你确定一组字段将有效地保持唯一性，仍然可以将这些字段用作自然键。</p>\n</aside>\n<p>对没有主键的对象的反序列化将始终检查模型的管理器是否具有 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_by_natural_key()</span></code> 方法，如果有，则使用它填充反序列化对象的主键。</p>\n</section>\n<section id=\"serialization-of-natural-keys\">\n<h3>自然键序列化<a class=\"heading-anchor\" href=\"#serialization-of-natural-keys\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>那么如何在序列化对象时让 Django 发出自然键？首先，你需要添加另一种方法，这一次是向模型本身添加：</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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">birthdate</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"n\">PersonManager</span><span class=\"p\">()</span>\n\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">constraints</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n            <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">UniqueConstraint</span><span class=\"p\">(</span>\n                <span class=\"n\">fields</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;first_name&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;last_name&quot;</span><span class=\"p\">],</span>\n                <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;unique_first_last_name&quot;</span><span class=\"p\">,</span>\n            <span class=\"p\">),</span>\n        <span class=\"p\">]</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">natural_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">first_name</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_name</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>该方法应该始终返回一个自然键元组 -- 在这个示例中是 <code class=\"docutils literal notranslate\"><span class=\"pre\">(名，姓)</span></code>。然后，在调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">serializers.serialize()</span></code> 时，你提供 <code class=\"docutils literal notranslate\"><span class=\"pre\">use_natural_foreign_keys=True</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">use_natural_primary_keys=True</span></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=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"s2\">&quot;json&quot;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>    <span class=\"p\">[</span><span class=\"n\">book1</span><span class=\"p\">,</span> <span class=\"n\">book2</span><span class=\"p\">],</span>\n<span class=\"gp\">... </span>    <span class=\"n\">indent</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>    <span class=\"n\">use_natural_foreign_keys</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>    <span class=\"n\">use_natural_primary_keys</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n</code></pre></div>\n<p>当指定 <code class=\"docutils literal notranslate\"><span class=\"pre\">use_natural_foreign_keys=True</span></code> 时，Django 将使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">natural_key()</span></code> 方法将任何外键引用序列化为定义该方法的类型的对象。</p>\n<p>当指定 <code class=\"docutils literal notranslate\"><span class=\"pre\">use_natural_primary_keys=True</span></code> 时，Django 不会在该对象的序列化数据中提供主键，因为它可以在反序列化期间进行计算：</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=\"o\">...</span>\n<span class=\"p\">{</span>\n    <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;store.person&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;first_name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Douglas&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;last_name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Adams&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;birth_date&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;1952-03-11&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">}</span>\n<span class=\"o\">...</span>\n</code></pre></div>\n<p>当需要将序列化数据加载到现有数据库中，并且无法保证序列化的主键值尚未使用，并且不需要确保反序列化对象保留相同的主键时，这一点非常有用。</p>\n<p>如果你使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#django-admin-dumpdata\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">dumpdata</span></code></a> 生成序列化数据，使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#cmdoption-dumpdata-natural-foreign\"><code class=\"xref std std-option docutils literal notranslate\"><span class=\"pre\">dumpdata</span> <span class=\"pre\">--natural-foreign</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#cmdoption-dumpdata-natural-primary\"><code class=\"xref std std-option docutils literal notranslate\"><span class=\"pre\">dumpdata</span> <span class=\"pre\">--natural-primary</span></code></a> 命令行标志生成自然键。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>你不需要同时定义 <code class=\"docutils literal notranslate\"><span class=\"pre\">natural_key()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_by_natural_key()</span></code>。如果你不想要 Django 在序列化期间输出自然键，但希望保留加载自然键的能力，那你可以选择不实现 <code class=\"docutils literal notranslate\"><span class=\"pre\">natural_key()</span></code> 方法。</p>\n<p>相反，如果（出于某些奇怪的原因）你想要 Django 在序列化时输出自然键，但是 <em>不</em> 加载那些键值，只需要不定义 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_by_natural_key()</span></code> 方法。</p>\n</aside>\n</section>\n<section id=\"natural-keys-and-forward-references\">\n<span id=\"id5\"></span><h3>自然键和前向引用<a class=\"heading-anchor\" href=\"#natural-keys-and-forward-references\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>有时当你使用 <a class=\"reference internal\" href=\"#topics-serialization-natural-keys\"><span class=\"std std-ref\">自然外键</span></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=\"o\">...</span>\n<span class=\"p\">{</span>\n    <span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;store.book&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Mostly Harmless&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;author&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Douglas&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Adams&quot;</span><span class=\"p\">]},</span>\n<span class=\"p\">},</span>\n<span class=\"o\">...</span>\n<span class=\"p\">{</span><span class=\"s2\">&quot;model&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;store.person&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;fields&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;first_name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Douglas&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;last_name&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;Adams&quot;</span><span class=\"p\">}},</span>\n<span class=\"o\">...</span>\n</code></pre></div>\n<p>为了处理这种情况，你需要将 <code class=\"docutils literal notranslate\"><span class=\"pre\">handle_forward_references=True</span></code> 传入 <code class=\"docutils literal notranslate\"><span class=\"pre\">serializers.deserialize()</span></code>。这将在 <code class=\"docutils literal notranslate\"><span class=\"pre\">DeserializedObject</span></code> 实例上设置 <code class=\"docutils literal notranslate\"><span class=\"pre\">deferred_fields</span></code> 属性。你需要保持追踪该属性不是 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">DeserializedObject</span></code> 实例并在之后调用它们的 <code class=\"docutils literal notranslate\"><span class=\"pre\">save_deferred_fields()</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\">objs_with_deferred_fields</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n<span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">deserialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;xml&quot;</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">handle_forward_references</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">):</span>\n    <span class=\"n\">obj</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"n\">obj</span><span class=\"o\">.</span><span class=\"n\">deferred_fields</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n        <span class=\"n\">objs_with_deferred_fields</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">objs_with_deferred_fields</span><span class=\"p\">:</span>\n    <span class=\"n\">obj</span><span class=\"o\">.</span><span class=\"n\">save_deferred_fields</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>要使其工作，引用模型上的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code> 必须具有 <code class=\"docutils literal notranslate\"><span class=\"pre\">null=True</span></code>。</p>\n</section>\n<section id=\"dependencies-during-serialization\">\n<h3>序列化期间的依赖项<a class=\"heading-anchor\" href=\"#dependencies-during-serialization\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>通过注意辅助工具中中对象的顺序，通常可以避免显式地处理前向引用。</p>\n<p>为了帮助实现这一点，在序列化标准主键对象之前，使用 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#cmdoption-dumpdata-natural-foreign\"><code class=\"xref std std-option docutils literal notranslate\"><span class=\"pre\">dumpdata</span> <span class=\"pre\">--natural-foreign</span></code></a> 选项对 <a class=\"reference internal\" href=\"/zh-hans/5.0/ref/django-admin/#django-admin-dumpdata\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">dumpdata</span></code></a>  的调用将使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">natural_key()</span></code> 方法对任何模型进行序列化。</p>\n<p>但是，这可能并不总是足够的。如果您的自然键引用了另一个对象（通过使用外键或另一个对象的自然键作为自然键的一部分），那么你需要确保自然键所依赖的对象出现在序列化数据中在自然键要求它们之前。</p>\n<p>要控制此顺序，你可以在 <code class=\"docutils literal notranslate\"><span class=\"pre\">natural_key()</span></code> 方法中定义依赖。为此可以在  <code class=\"docutils literal notranslate\"><span class=\"pre\">natural_key()</span></code> 方法本身上设置一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">dependencies</span></code> 属性。</p>\n<p>例如，让我们为上面示例中的 <code class=\"docutils literal notranslate\"><span class=\"pre\">Book</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\">class</span><span class=\"w\"> </span><span class=\"nc\">Book</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\">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=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n    <span class=\"n\">author</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Person</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">natural_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,)</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">author</span><span class=\"o\">.</span><span class=\"n\">natural_key</span><span class=\"p\">()</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">Book</span></code> 的自然键是书名和作者的组合。这意味着 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 必须在 <code class=\"docutils literal notranslate\"><span class=\"pre\">Book</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\">natural_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,)</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">author</span><span class=\"o\">.</span><span class=\"n\">natural_key</span><span class=\"p\">()</span>\n\n\n<span class=\"n\">natural_key</span><span class=\"o\">.</span><span class=\"n\">dependencies</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;example_app.person&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>这个定义确保了所有 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 对象在任何 <code class=\"docutils literal notranslate\"><span class=\"pre\">Book</span></code> 对象之前序列化。反过来，任何对象引用了 <code class=\"docutils literal notranslate\"><span class=\"pre\">Book</span></code> 都将在 <code class=\"docutils literal notranslate\"><span class=\"pre\">Person</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Book</span></code> 被序列化完后再序列化。</p>\n</section>\n</section>","rootId":"serializing-django-objects","toc":[{"title":"序列化数据","anchor":"serializing-data","children":[{"title":"字段子集","anchor":"subset-of-fields","children":[]},{"title":"继承来的模型","anchor":"inherited-models","children":[]}]},{"title":"反序列化数据","anchor":"deserializing-data","children":[]},{"title":"序列化格式","anchor":"serialization-formats","children":[{"title":"XML","anchor":"xml","children":[]},{"title":"JSON","anchor":"serialization-formats-json","children":[{"title":"DjangoJSONEncoder","anchor":"djangojsonencoder","children":[]}]},{"title":"JSONL","anchor":"serialization-formats-jsonl","children":[]},{"title":"YAML","anchor":"yaml","children":[]}]},{"title":"自然键","anchor":"natural-keys","children":[{"title":"自然键反序列化","anchor":"deserialization-of-natural-keys","children":[]},{"title":"自然键序列化","anchor":"serialization-of-natural-keys","children":[]},{"title":"自然键和前向引用","anchor":"natural-keys-and-forward-references","children":[]},{"title":"序列化期间的依赖项","anchor":"dependencies-during-serialization","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/5.0/topics/"}],"prev":{"docname":"topics/performance","title":"性能和优化","url":"/zh-hans/5.0/topics/performance/"},"next":{"docname":"topics/settings","title":"Django 配置","url":"/zh-hans/5.0/topics/settings/"},"formats":{"html":"/zh-hans/5.0/topics/serialization/","markdown":"/zh-hans/5.0/topics/serialization.md","json":"/zh-hans/5.0/topics/serialization.json"},"source":"https://github.com/django/django/blob/stable/5.0.x/docs/topics/serialization.txt","official":"https://docs.djangoproject.com/zh-hans/5.0/topics/serialization/","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"]}