“Django/docs/2.2.x/topics/serialization”的版本间差异

来自菜鸟教程
Django/docs/2.2.x/topics/serialization
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:序列化 Django 对象 — Django 文档}}
 
<div id="serializing-django-objects" class="section">
 
<div id="serializing-django-objects" class="section">
  
= Serializing Django objects =
+
= 序列化 Django 对象 =
  
Django's serialization framework provides a mechanism for &quot;translating&quot; Django
+
Django 的序列化框架提供了一种将 Django 模型“翻译”成其他格式的机制。 通常这些其他格式将基于文本并用于通过线路发送 Django 数据,但序列化程序可以处理任何格式(基于文本或非文本)。
models into other formats. Usually these other formats will be text-based and
 
used for sending Django data over a wire, but it's possible for a
 
serializer to handle any format (text-based or not).
 
  
 
<div class="admonition seealso">
 
<div class="admonition seealso">
  
参见
+
也可以看看
  
If you just want to get some data from your tables into a serialized
+
如果你只是想从你的表中获取一些数据到序列化的形式,你可以使用 [[#id1|:djadmin:`dumpdata`]] 管理命令。
form, you could use the [[../../ref/django-admin#django-admin-dumpdata|<code>dumpdata</code>]] management command.
 
  
  
第19行: 第16行:
 
<div id="serializing-data" class="section">
 
<div id="serializing-data" class="section">
  
== Serializing data ==
+
== 序列化数据 ==
  
At the highest level, serializing data is a very simple operation:
+
在最高级别,序列化数据是一个非常简单的操作:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第27行: 第24行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.core import serializers
+
<syntaxhighlight lang="python">from django.core import serializers
data = serializers.serialize(&quot;xml&quot;, SomeModel.objects.all())</pre>
+
data = serializers.serialize("xml", SomeModel.objects.all())</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The arguments to the <code>serialize</code> function are the format to serialize the data
+
<code>serialize</code> 函数的参数是将数据序列化为的格式(请参阅 [[#id4|序列化格式]] )和要序列化的 [[../../ref/models/querysets#django.db.models.query|QuerySet]]。 (实际上,第二个参数可以是任何生成 Django 模型实例的迭代器,但它几乎总是一个 QuerySet)。
to (see [[#id2|Serialization formats]]) and a
 
[[../../ref/models/querysets#django.db.models.query|<code>QuerySet</code>]] to serialize. (Actually, the second
 
argument can be any iterator that yields Django model instances, but it'll
 
almost always be a QuerySet).
 
  
; <code>django.core.serializers.</code><code>get_serializer</code><span class="sig-paren">(</span>''<span class="n">format</span>''<span class="sig-paren">)</span>
+
; <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>''<span class="n"><span class="pre">format</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
You can also use a serializer object directly:
+
您还可以直接使用序列化程序对象:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第48行: 第41行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>XMLSerializer = serializers.get_serializer(&quot;xml&quot;)
+
<syntaxhighlight lang="python">XMLSerializer = serializers.get_serializer("xml")
 
xml_serializer = XMLSerializer()
 
xml_serializer = XMLSerializer()
 
xml_serializer.serialize(queryset)
 
xml_serializer.serialize(queryset)
data = xml_serializer.getvalue()</pre>
+
data = xml_serializer.getvalue()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This is useful if you want to serialize data directly to a file-like object
+
如果您想将数据直接序列化为类似文件的对象(包括 [[../../ref/request-response#django.http|HttpResponse]]),这将非常有用:
(which includes an [[../../ref/request-response#django.http|<code>HttpResponse</code>]]):
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第63行: 第55行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>with open(&quot;file.xml&quot;, &quot;w&quot;) as out:
+
<syntaxhighlight lang="python">with open("file.xml", "w") as out:
     xml_serializer.serialize(SomeModel.objects.all(), stream=out)</pre>
+
     xml_serializer.serialize(SomeModel.objects.all(), stream=out)</syntaxhighlight>
  
 
</div>
 
</div>
第71行: 第63行:
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
Calling [[#django.core.serializers.get_serializer|<code>get_serializer()</code>]] with an unknown
+
使用未知的 [[#serialization-formats|格式]] 调用 [[#django.core.serializers.get_serializer|get_serializer()]] 将引发 <code>django.core.serializers.SerializerDoesNotExist</code> 异常。
[[#serialization-formats|<span class="std std-ref">format</span>]] will raise a
 
<code>django.core.serializers.SerializerDoesNotExist</code> exception.
 
  
  
第81行: 第71行:
 
<div id="subset-of-fields" class="section">
 
<div id="subset-of-fields" class="section">
  
<span id="id1"></span>
+
<span id="id3"></span>
=== Subset of fields ===
+
=== 字段子集 ===
  
If you only want a subset of fields to be serialized, you can
+
如果您只想序列化字段的子集,则可以为序列化程序指定 <code>fields</code> 参数:
specify a <code>fields</code> argument to the serializer:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第91行: 第80行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.core import serializers
+
<syntaxhighlight lang="python">from django.core import serializers
data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))</pre>
+
data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In this example, only the <code>name</code> and <code>size</code> attributes of each model will
+
在本例中,只会序列化每个模型的 <code>name</code> <code>size</code> 属性。 主键始终序列化为结果输出中的 <code>pk</code> 元素; 它从未出现在 <code>fields</code> 部分。
be serialized. The primary key is always serialized as the <code>pk</code> element in the
 
resulting output; it never appears in the <code>fields</code> part.
 
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
Depending on your model, you may find that it is not possible to
+
根据您的模型,您可能会发现无法反序列化仅序列化其字段子集的模型。 如果序列化对象没有指定模型所需的所有字段,反序列化器将无法保存反序列化实例。
deserialize a model that only serializes a subset of its fields. If a
 
serialized object doesn't specify all the fields that are required by a
 
model, the deserializer will not be able to save deserialized instances.
 
  
  
第116行: 第100行:
 
<div id="inherited-models" class="section">
 
<div id="inherited-models" class="section">
  
=== Inherited models ===
+
=== 继承模型 ===
  
If you have a model that is defined using an [[../db/models#abstract-base-classes|<span class="std std-ref">abstract base class</span>]], you don't have to do anything special to serialize
+
如果您有一个使用 [[../db/models#abstract-base-classes|抽象基类]] 定义的模型,则无需执行任何特殊操作即可序列化该模型。 只需在要序列化的对象(或多个对象)上调用序列化程序,输出将是序列化对象的完整表示。
that model. Just call the serializer on the object (or objects) that you want to
 
serialize, and the output will be a complete representation of the serialized
 
object.
 
  
However, if you have a model that uses [[../db/models#multi-table-inheritance|<span class="std std-ref">multi-table inheritance</span>]], you also need to serialize all of the base classes
+
但是,如果您有一个使用 [[../db/models#multi-table-inheritance|多表继承]] 的模型,您还需要序列化该模型的所有基类。 这是因为只有在模型上本地定义的字段才会被序列化。 例如,考虑以下模型:
for the model. This is because only the fields that are locally defined on the
 
model will be serialized. For example, consider the following models:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第131行: 第110行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>class Place(models.Model):
+
<syntaxhighlight lang="python">class Place(models.Model):
 
     name = models.CharField(max_length=50)
 
     name = models.CharField(max_length=50)
  
 
class Restaurant(Place):
 
class Restaurant(Place):
     serves_hot_dogs = models.BooleanField(default=False)</pre>
+
     serves_hot_dogs = models.BooleanField(default=False)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If you only serialize the Restaurant model:
+
如果您只序列化 Restaurant 模型:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第146行: 第125行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>data = serializers.serialize('xml', Restaurant.objects.all())</pre>
+
<syntaxhighlight lang="python">data = serializers.serialize('xml', Restaurant.objects.all())</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
the fields on the serialized output will only contain the <code>serves_hot_dogs</code>
+
序列化输出上的字段将仅包含 <code>serves_hot_dogs</code> 属性。 基类的 <code>name</code> 属性将被忽略。
attribute. The <code>name</code> attribute of the base class will be ignored.
 
  
In order to fully serialize your <code>Restaurant</code> instances, you will need to
+
为了完全序列化您的 <code>Restaurant</code> 实例,您还需要序列化 <code>Place</code> 模型:
serialize the <code>Place</code> models as well:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第161行: 第138行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>all_objects = [*Restaurant.objects.all(), *Place.objects.all()]
+
<syntaxhighlight lang="python">all_objects = [*Restaurant.objects.all(), *Place.objects.all()]
data = serializers.serialize('xml', all_objects)</pre>
+
data = serializers.serialize('xml', all_objects)</syntaxhighlight>
  
 
</div>
 
</div>
第173行: 第150行:
 
<div id="deserializing-data" class="section">
 
<div id="deserializing-data" class="section">
  
== Deserializing data ==
+
== 反序列化数据 ==
  
Deserializing data is also a fairly simple operation:
+
反序列化数据也是一个相当简单的操作:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第181行: 第158行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>for obj in serializers.deserialize(&quot;xml&quot;, data):
+
<syntaxhighlight lang="python">for obj in serializers.deserialize("xml", data):
     do_something_with(obj)</pre>
+
     do_something_with(obj)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
As you can see, the <code>deserialize</code> function takes the same format argument as
+
如您所见,<code>deserialize</code> 函数采用与 <code>serialize</code> 相同的格式参数,一个字符串或数据流,并返回一个迭代器。
<code>serialize</code>, a string or stream of data, and returns an iterator.
 
  
However, here it gets slightly complicated. The objects returned by the
+
然而,这里有点复杂。 <code>deserialize</code> 迭代器 ''返回的对象不是'' 简单的 Django 对象。 相反,它们是特殊的 <code>DeserializedObject</code> 实例,用于包装已创建但未保存的对象和任何关联的关系数据。
<code>deserialize</code> iterator ''aren't'' simple Django objects. Instead, they are
 
special <code>DeserializedObject</code> instances that wrap a created -- but unsaved --
 
object and any associated relationship data.
 
  
Calling <code>DeserializedObject.save()</code> saves the object to the database.
+
调用 <code>DeserializedObject.save()</code> 将对象保存到数据库中。
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
If the <code>pk</code> attribute in the serialized data doesn't exist or is
+
如果序列化数据中的 <code>pk</code> 属性不存在或为空,则将新实例保存到数据库中。
null, a new instance will be saved to the database.
 
  
  
 
</div>
 
</div>
This ensures that deserializing is a non-destructive operation even if the
+
这确保了反序列化是一种非破坏性操作,即使序列化表示中的数据与数据库中当前的数据不匹配。 通常,使用这些 <code>DeserializedObject</code> 实例看起来像:
data in your serialized representation doesn't match what's currently in the
 
database. Usually, working with these <code>DeserializedObject</code> instances looks
 
something like:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第215行: 第184行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>for deserialized_object in serializers.deserialize(&quot;xml&quot;, data):
+
<syntaxhighlight lang="python">for deserialized_object in serializers.deserialize("xml", data):
 
     if object_should_be_saved(deserialized_object):
 
     if object_should_be_saved(deserialized_object):
         deserialized_object.save()</pre>
+
         deserialized_object.save()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In other words, the usual use is to examine the deserialized objects to make
+
换句话说,通常的用途是检查反序列化的对象,以确保它们在执行之前“适合”保存。 当然,如果您信任您的数据源,您可以保存对象并继续。
sure that they are &quot;appropriate&quot; for saving before doing so. Of course, if you
 
trust your data source you could just save the object and move on.
 
  
The Django object itself can be inspected as <code>deserialized_object.object</code>.
+
Django 对象本身可以被检查为 <code>deserialized_object.object</code>。 如果序列化数据中的字段在模型上不存在,除非将 <code>ignorenonexistent</code> 参数作为 <code>True</code> 传入,否则将引发 <code>DeserializationError</code>
If fields in the serialized data do not exist on a model, a
 
<code>DeserializationError</code> will be raised unless the <code>ignorenonexistent</code>
 
argument is passed in as <code>True</code>:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第235行: 第199行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>serializers.deserialize(&quot;xml&quot;, data, ignorenonexistent=True)</pre>
+
<syntaxhighlight lang="python">serializers.deserialize("xml", data, ignorenonexistent=True)</syntaxhighlight>
  
 
</div>
 
</div>
第244行: 第208行:
 
<div id="serialization-formats" class="section">
 
<div id="serialization-formats" class="section">
  
<span id="id2"></span>
+
<span id="id4"></span>
== Serialization formats ==
+
== 序列化格式 ==
  
Django supports a number of serialization formats, some of which require you
+
Django 支持多种序列化格式,其中一些需要您安装第三方 Python 模块:
to install third-party Python modules:
 
  
 
{|
 
{|
!width="14%"| Identifier
+
!width="14%"| 标识符
!width="86%"| Information
+
!width="86%"| 信息
 
|-
 
|-
 
| <code>xml</code>
 
| <code>xml</code>
| Serializes to and from a simple XML dialect.
+
| 与简单的 XML 方言之间进行序列化。
 
|-
 
|-
 
| <code>json</code>
 
| <code>json</code>
| Serializes to and from [https://json.org/ JSON].
+
| [https://json.org/ JSON] 之间的序列化。
 
|-
 
|-
 
| <code>yaml</code>
 
| <code>yaml</code>
| Serializes to YAML (YAML Ain't a Markup Language). This
+
| 序列化为 YAML(YAML 不是标记语言)。 此序列化程序仅在安装了 [https://pyyaml.org/ PyYAML] 时可用。
serializer is only available if [https://pyyaml.org/ PyYAML] is installed.
 
 
|}
 
|}
  
第269行: 第231行:
 
=== XML ===
 
=== XML ===
  
The basic XML serialization format is quite simple:
+
基本的 XML 序列化格式非常简单:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第275行: 第237行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+
<syntaxhighlight lang="python"><?xml version="1.0" encoding="utf-8"?>
&lt;django-objects version=&quot;1.0&quot;&gt;
+
<django-objects version="1.0">
     &lt;object pk=&quot;123&quot; model=&quot;sessions.session&quot;&gt;
+
     <object pk="123" model="sessions.session">
         &lt;field type=&quot;DateTimeField&quot; name=&quot;expire_date&quot;&gt;2013-01-16T08:16:59.844560+00:00&lt;/field&gt;
+
         <field type="DateTimeField" name="expire_date">2013-01-16T08:16:59.844560+00:00</field>
         &lt;!-- ... --&gt;
+
         <!-- ... -->
     &lt;/object&gt;
+
     </object>
&lt;/django-objects&gt;</pre>
+
</django-objects></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The whole collection of objects that is either serialized or deserialized is
+
序列化或反序列化的整个对象集合由包含多个 <code>&lt;object&gt;</code> 元素的 <code>&lt;django-objects&gt;</code> 标签表示。 每个这样的对象都有两个属性:“pk”和“model”,后者由应用程序的名称(“sessions”)和模型的小写名称(“session”)表示,中间用点分隔。
represented by a <code>&lt;django-objects&gt;</code>-tag which contains multiple
 
<code>&lt;object&gt;</code>-elements. Each such object has two attributes: &quot;pk&quot; and &quot;model&quot;,
 
the latter being represented by the name of the app (&quot;sessions&quot;) and the
 
lowercase name of the model (&quot;session&quot;) separated by a dot.
 
  
Each field of the object is serialized as a <code>&lt;field&gt;</code>-element sporting the
+
对象的每个字段都被序列化为一个 <code>&lt;field&gt;</code> 元素,其中包含字段“类型”和“名称”。 元素的文本内容表示应该存储的值。
fields &quot;type&quot; and &quot;name&quot;. The text content of the element represents the value
 
that should be stored.
 
  
Foreign keys and other relational fields are treated a little bit differently:
+
外键和其他关系字段的处理方式略有不同:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第302行: 第258行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&lt;object pk=&quot;27&quot; model=&quot;auth.permission&quot;&gt;
+
<syntaxhighlight lang="python"><object pk="27" model="auth.permission">
     &lt;!-- ... --&gt;
+
     <!-- ... -->
     &lt;field to=&quot;contenttypes.contenttype&quot; name=&quot;content_type&quot; rel=&quot;ManyToOneRel&quot;&gt;9&lt;/field&gt;
+
     <field to="contenttypes.contenttype" name="content_type" rel="ManyToOneRel">9</field>
     &lt;!-- ... --&gt;
+
     <!-- ... -->
&lt;/object&gt;</pre>
+
</object></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In this example we specify that the <code>auth.Permission</code> object with the PK 27
+
在此示例中,我们指定具有 PK 27 的 <code>auth.Permission</code> 对象具有指向具有 PK 9 的 <code>contenttypes.ContentType</code> 实例的外键。
has a foreign key to the <code>contenttypes.ContentType</code> instance with the PK 9.
 
  
ManyToMany-relations are exported for the model that binds them. For instance,
+
为绑定它们的模型导出多对多关系。 例如,<code>auth.User</code> 模型与 <code>auth.Permission</code> 模型有这样的关系:
the <code>auth.User</code> model has such a relation to the <code>auth.Permission</code> model:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第321行: 第275行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&lt;object pk=&quot;1&quot; model=&quot;auth.user&quot;&gt;
+
<syntaxhighlight lang="python"><object pk="1" model="auth.user">
     &lt;!-- ... --&gt;
+
     <!-- ... -->
     &lt;field to=&quot;auth.permission&quot; name=&quot;user_permissions&quot; rel=&quot;ManyToManyRel&quot;&gt;
+
     <field to="auth.permission" name="user_permissions" rel="ManyToManyRel">
         &lt;object pk=&quot;46&quot;&gt;&lt;/object&gt;
+
         <object pk="46"></object>
         &lt;object pk=&quot;47&quot;&gt;&lt;/object&gt;
+
         <object pk="47"></object>
     &lt;/field&gt;
+
     </field>
&lt;/object&gt;</pre>
+
</object></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This example links the given user with the permission models with PKs 46 and 47.
+
此示例将给定用户与具有 PK 46 47 的权限模型相关联。
  
 
<div class="admonition-control-characters admonition">
 
<div class="admonition-control-characters admonition">
  
Control characters
+
控制字符
  
If the content to be serialized contains control characters that are not
+
如果要序列化的内容包含 XML 1.0 标准中不接受的控制字符,则序列化将失败并出现 <code>ValueError</code> 异常。 另请阅读 W3C [https://www.w3.org/International/questions/qa-controls HTML、XHTML、XML 和控制代码] 的解释。
accepted in the XML 1.0 standard, the serialization will fail with a
 
<code>ValueError</code> exception. Read also the W3C's explanation of [https://www.w3.org/International/questions/qa-controls HTML,
 
XHTML, XML and Control Codes].
 
  
  
第349行: 第300行:
 
<div id="serialization-formats-json" class="section">
 
<div id="serialization-formats-json" class="section">
  
<span id="id3"></span>
+
<span id="id5"></span>
 
=== JSON ===
 
=== JSON ===
  
When staying with the same example data as before it would be serialized as
+
当使用与之前相同的示例数据时,它将按以下方式序列化为 JSON:
JSON in the following way:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第359行: 第309行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>[
+
<syntaxhighlight lang="python">[
 
     {
 
     {
         &quot;pk&quot;: &quot;4b678b301dfd8a4e0dad910de3ae245b&quot;,
+
         "pk": "4b678b301dfd8a4e0dad910de3ae245b",
         &quot;model&quot;: &quot;sessions.session&quot;,
+
         "model": "sessions.session",
         &quot;fields&quot;: {
+
         "fields": {
             &quot;expire_date&quot;: &quot;2013-01-16T08:16:59.844Z&quot;,
+
             "expire_date": "2013-01-16T08:16:59.844Z",
 
             ...
 
             ...
 
         }
 
         }
 
     }
 
     }
]</pre>
+
]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The formatting here is a bit simpler than with XML. The whole collection
+
此处的格式设置比 XML 简单一些。 整个集合仅表示为一个数组,对象由具有三个属性的 JSON 对象表示:“pk”、“model”和“fields”。 “fields”也是一个对象,分别包含每个字段的名称和值作为属性和属性值。
is just represented as an array and the objects are represented by JSON objects
 
with three properties: &quot;pk&quot;, &quot;model&quot; and &quot;fields&quot;. &quot;fields&quot; is again an object
 
containing each field's name and value as property and property-value
 
respectively.
 
  
Foreign keys just have the PK of the linked object as property value.
+
外键只是将链接对象的 PK 作为属性值。 ManyToMany 关系针对定义它们的模型进行序列化,并表示为 PK 列表。
ManyToMany-relations are serialized for the model that defines them and are
 
represented as a list of PKs.
 
  
Be aware that not all Django output can be passed unmodified to <code>json</code>.
+
请注意,并非所有 Django 输出都可以不加修改地传递给 <code>json</code>。 例如,如果要序列化的对象中有一些自定义类型,则必须为其编写自定义 <code>json</code> 编码器。 像这样的事情会起作用:
For example, if you have some custom type in an object to be serialized, you'll
 
have to write a custom <code>json</code> encoder for it. Something like this will
 
work:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第392行: 第333行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.core.serializers.json import DjangoJSONEncoder
+
<syntaxhighlight lang="python">from django.core.serializers.json import DjangoJSONEncoder
  
 
class LazyEncoder(DjangoJSONEncoder):
 
class LazyEncoder(DjangoJSONEncoder):
第398行: 第339行:
 
         if isinstance(obj, YourCustomType):
 
         if isinstance(obj, YourCustomType):
 
             return str(obj)
 
             return str(obj)
         return super().default(obj)</pre>
+
         return super().default(obj)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You can then pass <code>cls=LazyEncoder</code> to the <code>serializers.serialize()</code>
+
然后,您可以将 <code>cls=LazyEncoder</code> 传递给 <code>serializers.serialize()</code> 函数:
function:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第410行: 第350行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.core.serializers import serialize
+
<syntaxhighlight lang="python">from django.core.serializers import serialize
  
serialize('json', SomeModel.objects.all(), cls=LazyEncoder)</pre>
+
serialize('json', SomeModel.objects.all(), cls=LazyEncoder)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Also note that GeoDjango provides a [[../../ref/contrib/gis/serializers|<span class="doc">customized GeoJSON serializer</span>]].
+
另请注意,GeoDjango 提供了 [[../../ref/contrib/gis/serializers|自定义 GeoJSON 序列化程序]]
  
 
<div id="djangojsonencoder" class="section">
 
<div id="djangojsonencoder" class="section">
  
==== <code>DjangoJSONEncoder</code> ====
+
==== DjangoJSONEncoder ====
  
; ''class'' <code>django.core.serializers.json.</code><code>DjangoJSONEncoder</code>
+
; ''<span class="pre">class</span>'' <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>
 
:  
 
:  
  
The JSON serializer uses <code>DjangoJSONEncoder</code> for encoding. A subclass of
+
JSON 序列化程序使用 <code>DjangoJSONEncoder</code> 进行编码。 <code>JSONEncoder</code> 的子类,它处理这些附加类型:
<code>JSONEncoder</code>, it handles these additional types:
 
  
 
; <code>datetime</code>
 
; <code>datetime</code>
: A string of the form <code>YYYY-MM-DDTHH:mm:ss.sssZ</code> or <code>YYYY-MM-DDTHH:mm:ss.sss+HH:MM</code> as defined in [https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 ECMA-262].
+
: [https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 ECMA-262] 中定义的 <code>YYYY-MM-DDTHH:mm:ss.sssZ</code> <code>YYYY-MM-DDTHH:mm:ss.sss+HH:MM</code> 形式的字符串。
 
; <code>date</code>
 
; <code>date</code>
: A string of the form <code>YYYY-MM-DD</code> as defined in [https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 ECMA-262].
+
: [https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 ECMA-262] 中定义的 <code>YYYY-MM-DD</code> 形式的字符串。
 
; <code>time</code>
 
; <code>time</code>
: A string of the form <code>HH:MM:ss.sss</code> as defined in [https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 ECMA-262].
+
: [https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 ECMA-262] 中定义的 <code>HH:MM:ss.sss</code> 形式的字符串。
 
; <code>timedelta</code>
 
; <code>timedelta</code>
: A string representing a duration as defined in ISO-8601. For example, <code>timedelta(days=1, hours=2, seconds=3.4)</code> is represented as <code>'P1DT02H00M03.400000S'</code>.
+
: 表示 ISO-8601 中定义的持续时间的字符串。 例如,<code>timedelta(days=1, hours=2, seconds=3.4)</code> 表示为 <code>'P1DT02H00M03.400000S'</code>
; <code>Decimal</code>, <code>Promise</code> (<code>django.utils.functional.lazy()</code> objects), <code>UUID</code>
+
; <code>Decimal</code><code>Promise</code><code>django.utils.functional.lazy()</code> 对象)、<code>UUID</code>
: A string representation of the object.
+
: 对象的字符串表示形式。
  
  
第448行: 第387行:
 
=== YAML ===
 
=== YAML ===
  
YAML serialization looks quite similar to JSON. The object list is serialized
+
YAML 序列化看起来与 JSON 非常相似。 对象列表被序列化为具有键“pk”、“模型”和“字段”的序列映射。 每个字段又是一个映射,键是字段名,值是值:
as a sequence mappings with the keys &quot;pk&quot;, &quot;model&quot; and &quot;fields&quot;. Each field is
 
again a mapping with the key being name of the field and the value the value:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第456行: 第393行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>-  fields: {expire_date: !!timestamp '2013-01-16 08:16:59.844560+00:00'}
+
<syntaxhighlight lang="python">-  fields: {expire_date: !!timestamp '2013-01-16 08:16:59.844560+00:00'}
 
     model: sessions.session
 
     model: sessions.session
     pk: 4b678b301dfd8a4e0dad910de3ae245b</pre>
+
     pk: 4b678b301dfd8a4e0dad910de3ae245b</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Referential fields are again just represented by the PK or sequence of PKs.
+
引用字段再次仅由 PK 或 PK 序列表示。
  
  
第472行: 第409行:
  
 
<span id="topics-serialization-natural-keys"></span>
 
<span id="topics-serialization-natural-keys"></span>
== Natural keys ==
+
== 自然键 ==
  
The default serialization strategy for foreign keys and many-to-many relations
+
外键和多对多关系的默认序列化策略是序列化关系中对象的主键的值。 此策略适用于大多数对象,但在某些情况下可能会造成困难。
is to serialize the value of the primary key(s) of the objects in the relation.
 
This strategy works well for most objects, but it can cause difficulty in some
 
circumstances.
 
  
Consider the case of a list of objects that have a foreign key referencing
+
考虑具有引用 [[../../ref/contrib/contenttypes#django.contrib.contenttypes.models|ContentType]] 的外键的对象列表的情况。 如果您要序列化引用内容类型的对象,那么您需要有一种方法来引用该内容类型。 由于 <code>ContentType</code> 对象是 Django 在数据库同步过程中自动创建的,给定内容类型的主键不容易预测; 这将取决于 [[#id6|:djadmin:`migrate`]] 的执行方式和时间。 这适用于所有自动生成对象的模型,特别是包括 [[../../ref/contrib/auth#django.contrib.auth.models|Permission]][[../../ref/contrib/auth#django.contrib.auth.models|Group]] [[../../ref/contrib/auth#django.contrib.auth.models|User]]
[[../../ref/contrib/contenttypes#django.contrib.contenttypes.models|<code>ContentType</code>]]. If you're going to
 
serialize an object that refers to a content type, then you need to have a way
 
to refer to that content type to begin with. Since <code>ContentType</code> objects are
 
automatically created by Django during the database synchronization process,
 
the primary key of a given content type isn't easy to predict; it will
 
depend on how and when [[../../ref/django-admin#django-admin-migrate|<code>migrate</code>]] was executed. This is true for all
 
models which automatically generate objects, notably including
 
[[../../ref/contrib/auth#django.contrib.auth.models|<code>Permission</code>]],
 
[[../../ref/contrib/auth#django.contrib.auth.models|<code>Group</code>]], and
 
[[../../ref/contrib/auth#django.contrib.auth.models|<code>User</code>]].
 
  
 
<div class="admonition warning">
 
<div class="admonition warning">
第495行: 第419行:
 
警告
 
警告
  
You should never include automatically generated objects in a fixture or
+
您永远不应该在夹具或其他序列化数据中包含自动生成的对象。 偶然地,夹具中的主键可能与数据库中的主键匹配,并且加载夹具将不起作用。 在更可能的情况下,它们不匹配,夹具加载将失败并显示 [[../../ref/exceptions#django.db|IntegrityError]]
other serialized data. By chance, the primary keys in the fixture
 
may match those in the database and loading the fixture will
 
have no effect. In the more likely case that they don't match, the fixture
 
loading will fail with an [[../../ref/exceptions#django.db|<code>IntegrityError</code>]].
 
  
  
 
</div>
 
</div>
There is also the matter of convenience. An integer id isn't always
+
还有一个方便的问题。 整数 id 并不总是引用对象的最方便的方式; 有时,更自然的参考会有所帮助。
the most convenient way to refer to an object; sometimes, a
 
more natural reference would be helpful.
 
  
It is for these reasons that Django provides ''natural keys''. A natural
+
正是出于这些原因,Django 提供了 ''自然键'' 。 自然键是一组值,可用于在不使用主键值的情况下唯一标识对象实例。
key is a tuple of values that can be used to uniquely identify an
 
object instance without using the primary key value.
 
  
 
<div id="deserialization-of-natural-keys" class="section">
 
<div id="deserialization-of-natural-keys" class="section">
  
=== Deserialization of natural keys ===
+
=== 自然键的反序列化 ===
  
Consider the following two models:
+
考虑以下两个模型:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第521行: 第437行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db import models
+
<syntaxhighlight lang="python">from django.db import models
  
 
class Person(models.Model):
 
class Person(models.Model):
第534行: 第450行:
 
class Book(models.Model):
 
class Book(models.Model):
 
     name = models.CharField(max_length=100)
 
     name = models.CharField(max_length=100)
     author = models.ForeignKey(Person, on_delete=models.CASCADE)</pre>
+
     author = models.ForeignKey(Person, on_delete=models.CASCADE)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Ordinarily, serialized data for <code>Book</code> would use an integer to refer to
+
通常,<code>Book</code> 的序列化数据将使用整数来指代作者。 例如,在 JSON 中,一本书可能被序列化为:
the author. For example, in JSON, a Book might be serialized as:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第546行: 第461行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>...
+
<syntaxhighlight lang="python">...
 
{
 
{
     &quot;pk&quot;: 1,
+
     "pk": 1,
     &quot;model&quot;: &quot;store.book&quot;,
+
     "model": "store.book",
     &quot;fields&quot;: {
+
     "fields": {
         &quot;name&quot;: &quot;Mostly Harmless&quot;,
+
         "name": "Mostly Harmless",
         &quot;author&quot;: 42
+
         "author": 42
 
     }
 
     }
 
}
 
}
...</pre>
+
...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This isn't a particularly natural way to refer to an author. It
+
这不是指代作者的一种特别自然的方式。 它要求您知道作者的主键值; 它还要求这个主键值是稳定的和可预测的。
requires that you know the primary key value for the author; it also
 
requires that this primary key value is stable and predictable.
 
  
However, if we add natural key handling to Person, the fixture becomes
+
但是,如果我们为 Person 添加自然键处理,则装置变得更加人性化。 要添加自然键处理,您可以使用 <code>get_by_natural_key()</code> 方法为 Person 定义一个默认管理器。 在 Person 的情况下,一个好的自然键可能是一对名字和姓氏:
much more humane. To add natural key handling, you define a default
 
Manager for Person with a <code>get_by_natural_key()</code> method. In the case
 
of a Person, a good natural key might be the pair of first and last
 
name:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第574行: 第483行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db import models
+
<syntaxhighlight lang="python">from django.db import models
  
 
class PersonManager(models.Manager):
 
class PersonManager(models.Manager):
第588行: 第497行:
  
 
     class Meta:
 
     class Meta:
         unique_together = [[../'first_name', 'last_name']]</pre>
+
         unique_together = [[../'first_name', 'last_name']]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Now books can use that natural key to refer to <code>Person</code> objects:
+
现在书籍可以使用该自然键来引用 <code>Person</code> 对象:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第599行: 第508行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>...
+
<syntaxhighlight lang="python">...
 
{
 
{
     &quot;pk&quot;: 1,
+
     "pk": 1,
     &quot;model&quot;: &quot;store.book&quot;,
+
     "model": "store.book",
     &quot;fields&quot;: {
+
     "fields": {
         &quot;name&quot;: &quot;Mostly Harmless&quot;,
+
         "name": "Mostly Harmless",
         &quot;author&quot;: [&quot;Douglas&quot;, &quot;Adams&quot;]
+
         "author": ["Douglas", "Adams"]
 
     }
 
     }
 
}
 
}
...</pre>
+
...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
When you try to load this serialized data, Django will use the
+
当您尝试加载这个序列化数据时,Django 将使用 <code>get_by_natural_key()</code> 方法将 <code>[&quot;Douglas&quot;, &quot;Adams&quot;]</code> 解析为实际 <code>Person</code> 对象的主键。
<code>get_by_natural_key()</code> method to resolve <code>[&quot;Douglas&quot;, &quot;Adams&quot;]</code>
 
into the primary key of an actual <code>Person</code> object.
 
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
Whatever fields you use for a natural key must be able to uniquely
+
用于自然键的任何字段都必须能够唯一标识一个对象。 这通常意味着您的模型将为您的自然键中的一个或多个字段提供一个唯一性子句(在单个字段上使用 unique=True,或者在多个字段上使用 <code>unique_together</code>)。 但是,不需要在数据库级别强制执行唯一性。 如果您确定一组字段实际上是唯一的,您仍然可以将这些字段用作自然键。
identify an object. This will usually mean that your model will
 
have a uniqueness clause (either unique=True on a single field, or
 
<code>unique_together</code> over multiple fields) for the field or fields
 
in your natural key. However, uniqueness doesn't need to be
 
enforced at the database level. If you are certain that a set of
 
fields will be effectively unique, you can still use those fields
 
as a natural key.
 
  
  
 
</div>
 
</div>
Deserialization of objects with no primary key will always check whether the
+
没有主键的对象的反序列化将始终检查模型的管理器是否有 <code>get_by_natural_key()</code> 方法,如果有,使用它来填充反序列化对象的主键。
model's manager has a <code>get_by_natural_key()</code> method and if so, use it to
 
populate the deserialized object's primary key.
 
  
  
第640行: 第538行:
 
<div id="serialization-of-natural-keys" class="section">
 
<div id="serialization-of-natural-keys" class="section">
  
=== Serialization of natural keys ===
+
=== 自然键的序列化 ===
  
So how do you get Django to emit a natural key when serializing an object?
+
那么如何让 Django 在序列化对象时发出自然键呢? 首先,您需要添加另一个方法——这次是添加到模型本身:
Firstly, you need to add another method -- this time to the model itself:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第649行: 第546行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>class Person(models.Model):
+
<syntaxhighlight lang="python">class Person(models.Model):
 
     first_name = models.CharField(max_length=100)
 
     first_name = models.CharField(max_length=100)
 
     last_name = models.CharField(max_length=100)
 
     last_name = models.CharField(max_length=100)
第660行: 第557行:
  
 
     def natural_key(self):
 
     def natural_key(self):
         return (self.first_name, self.last_name)</pre>
+
         return (self.first_name, self.last_name)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
That method should always return a natural key tuple -- in this
+
该方法应该总是返回一个自然键元组——在这个例子中,<code>(first name, last name)</code>。 然后,当您调用 <code>serializers.serialize()</code> 时,您提供 <code>use_natural_foreign_keys=True</code> <code>use_natural_primary_keys=True</code> 参数:
example, <code>(first name, last name)</code>. Then, when you call
 
<code>serializers.serialize()</code>, you provide <code>use_natural_foreign_keys=True</code>
 
or <code>use_natural_primary_keys=True</code> arguments:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第674行: 第568行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; serializers.serialize('json', [book1, book2], indent=2,
+
<syntaxhighlight lang="python">>>> serializers.serialize('json', [book1, book2], indent=2,
...      use_natural_foreign_keys=True, use_natural_primary_keys=True)</pre>
+
...      use_natural_foreign_keys=True, use_natural_primary_keys=True)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
When <code>use_natural_foreign_keys=True</code> is specified, Django will use the
+
当指定 <code>use_natural_foreign_keys=True</code> 时,Django 将使用 <code>natural_key()</code> 方法将任何外键引用序列化到定义该方法的类型的对象。
<code>natural_key()</code> method to serialize any foreign key reference to objects
 
of the type that defines the method.
 
  
When <code>use_natural_primary_keys=True</code> is specified, Django will not provide the
+
当指定 <code>use_natural_primary_keys=True</code> 时,Django 不会在此对象的序列化数据中提供主键,因为它可以在反序列化过程中计算:
primary key in the serialized data of this object since it can be calculated
 
during deserialization:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第692行: 第582行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>...
+
<syntaxhighlight lang="python">...
 
{
 
{
     &quot;model&quot;: &quot;store.person&quot;,
+
     "model": "store.person",
     &quot;fields&quot;: {
+
     "fields": {
         &quot;first_name&quot;: &quot;Douglas&quot;,
+
         "first_name": "Douglas",
         &quot;last_name&quot;: &quot;Adams&quot;,
+
         "last_name": "Adams",
         &quot;birth_date&quot;: &quot;1952-03-11&quot;,
+
         "birth_date": "1952-03-11",
 
     }
 
     }
 
}
 
}
...</pre>
+
...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This can be useful when you need to load serialized data into an existing
+
当您需要将序列化数据加载到现有数据库中并且您不能保证序列化主键值尚未被使用,并且不需要确保反序列化对象保留相同的主键时,这会很有用。
database and you cannot guarantee that the serialized primary key value is not
 
already in use, and do not need to ensure that deserialized objects retain the
 
same primary keys.
 
  
If you are using [[../../ref/django-admin#django-admin-dumpdata|<code>dumpdata</code>]] to generate serialized data, use the
+
如果您使用 [[#id8|:djadmin:`dumpdata`]] 生成序列化数据,请使用 <code>dumpdata --natural-foreign</code> <code>dumpdata --natural-primary</code> 命令行标志生成自然键。
[[../../ref/django-admin#cmdoption-dumpdata-natural-foreign|<code>dumpdata --natural-foreign</code>]] and [[../../ref/django-admin#cmdoption-dumpdata-natural-primary|<code>dumpdata --natural-primary</code>]]
 
command line flags to generate natural keys.
 
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
You don't need to define both <code>natural_key()</code> and
+
您不需要同时定义 <code>natural_key()</code> <code>get_by_natural_key()</code>。 如果你不希望 Django 在序列化过程中输出自然键,但又想保留加载自然键的能力,那么你可以选择不实现 <code>natural_key()</code> 方法。
<code>get_by_natural_key()</code>. If you don't want Django to output
 
natural keys during serialization, but you want to retain the
 
ability to load natural keys, then you can opt to not implement
 
the <code>natural_key()</code> method.
 
  
Conversely, if (for some strange reason) you want Django to output
+
相反,如果(出于某种奇怪的原因)您希望 Django 在序列化期间输出自然键,但 ''not'' 能够加载这些键值,只需不要定义 <code>get_by_natural_key()</code> 方法。
natural keys during serialization, but ''not'' be able to load those
 
key values, just don't define the <code>get_by_natural_key()</code> method.
 
  
  
第735行: 第614行:
 
<div id="natural-keys-and-forward-references" class="section">
 
<div id="natural-keys-and-forward-references" class="section">
  
<span id="id4"></span>
+
<span id="id10"></span>
=== Natural keys and forward references ===
+
=== 自然键和前向引用 ===
  
 
<div class="versionadded">
 
<div class="versionadded">
  
 +
<span class="versionmodified added">2.2 版中的新功能。</span>
  
  
 
</div>
 
</div>
Sometimes when you use [[#topics-serialization-natural-keys|<span class="std std-ref">natural foreign keys</span>]] you'll need to deserialize data where
+
有时,当您使用 [[#topics-serialization-natural-keys|自然外键]] 时,您需要反序列化数据,其中一个对象的外键引用了另一个尚未反序列化的对象。 这称为“前向参考”。
an object has a foreign key referencing another object that hasn't yet been
 
deserialized. This is called a &quot;forward reference&quot;.
 
  
For instance, suppose you have the following objects in your fixture:
+
例如,假设您的夹具中有以下对象:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第753行: 第631行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>...
+
<syntaxhighlight lang="python">...
 
{
 
{
     &quot;model&quot;: &quot;store.book&quot;,
+
     "model": "store.book",
     &quot;fields&quot;: {
+
     "fields": {
         &quot;name&quot;: &quot;Mostly Harmless&quot;,
+
         "name": "Mostly Harmless",
         &quot;author&quot;: [&quot;Douglas&quot;, &quot;Adams&quot;]
+
         "author": ["Douglas", "Adams"]
 
     }
 
     }
 
},
 
},
 
...
 
...
 
{
 
{
     &quot;model&quot;: &quot;store.person&quot;,
+
     "model": "store.person",
     &quot;fields&quot;: {
+
     "fields": {
         &quot;first_name&quot;: &quot;Douglas&quot;,
+
         "first_name": "Douglas",
         &quot;last_name&quot;: &quot;Adams&quot;
+
         "last_name": "Adams"
 
     }
 
     }
 
},
 
},
...</pre>
+
...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In order to handle this situation, you need to pass
+
为了处理这种情况,您需要将 <code>handle_forward_references=True</code> 传递给 <code>serializers.deserialize()</code>。 这将在 <code>DeserializedObject</code> 实例上设置 <code>deferred_fields</code> 属性。 您需要跟踪此属性不是 <code>None</code> <code>DeserializedObject</code> 实例,然后在它们上调用 <code>save_deferred_fields()</code>
<code>handle_forward_references=True</code> to <code>serializers.deserialize()</code>. This will
 
set the <code>deferred_fields</code> attribute on the <code>DeserializedObject</code> instances.
 
You'll need to keep track of <code>DeserializedObject</code> instances where this
 
attribute isn't <code>None</code> and later call <code>save_deferred_fields()</code> on them.
 
  
Typical usage looks like this:
+
典型用法如下所示:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第786行: 第660行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>objs_with_deferred_fields = []
+
<syntaxhighlight lang="python">objs_with_deferred_fields = []
  
 
for obj in serializers.deserialize('xml', data, handle_forward_references=True):
 
for obj in serializers.deserialize('xml', data, handle_forward_references=True):
第794行: 第668行:
  
 
for obj in objs_with_deferred_fields:
 
for obj in objs_with_deferred_fields:
     obj.save_deferred_fields()</pre>
+
     obj.save_deferred_fields()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
For this to work, the <code>ForeignKey</code> on the referencing model must have
+
为此,参考模型上的 <code>ForeignKey</code> 必须具有 <code>null=True</code>
<code>null=True</code>.
 
  
  
第806行: 第679行:
 
<div id="dependencies-during-serialization" class="section">
 
<div id="dependencies-during-serialization" class="section">
  
=== Dependencies during serialization ===
+
=== 序列化期间的依赖 ===
  
It's often possible to avoid explicitly having to handle forward references by
+
通常可以通过注意夹具内对象的顺序来避免显式处理前向引用。
taking care with the ordering of objects within a fixture.
 
  
To help with this, calls to [[../../ref/django-admin#django-admin-dumpdata|<code>dumpdata</code>]] that use the [[../../ref/django-admin#cmdoption-dumpdata-natural-foreign|<code>dumpdata --natural-foreign</code>]] option will serialize any model with a <code>natural_key()</code>
+
为了解决这个问题,使用 <code>dumpdata --natural-foreign</code> 选项调用 [[#id11|:djadmin:`dumpdata`]] 将在序列化标准主键对象之前使用 <code>natural_key()</code> 方法序列化任何模型。
method before serializing standard primary key objects.
 
  
However, this may not always be enough. If your natural key refers to
+
然而,这可能并不总是足够的。 如果您的自然键引用另一个对象(通过使用另一个对象的外键或自然键作为自然键的一部分),那么您需要能够确保自然键所依赖的对象出现在序列化数据中在自然键需要它们之前。
another object (by using a foreign key or natural key to another object
 
as part of a natural key), then you need to be able to ensure that
 
the objects on which a natural key depends occur in the serialized data
 
before the natural key requires them.
 
  
To control this ordering, you can define dependencies on your
+
要控制此顺序,您可以定义对 <code>natural_key()</code> 方法的依赖关系。 您可以通过在 <code>natural_key()</code> 方法本身上设置 <code>dependencies</code> 属性来完成此操作。
<code>natural_key()</code> methods. You do this by setting a <code>dependencies</code>
 
attribute on the <code>natural_key()</code> method itself.
 
  
For example, let's add a natural key to the <code>Book</code> model from the
+
例如,让我们为上面示例中的 <code>Book</code> 模型添加一个自然键:
example above:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第831行: 第695行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>class Book(models.Model):
+
<syntaxhighlight lang="python">class Book(models.Model):
 
     name = models.CharField(max_length=100)
 
     name = models.CharField(max_length=100)
 
     author = models.ForeignKey(Person, on_delete=models.CASCADE)
 
     author = models.ForeignKey(Person, on_delete=models.CASCADE)
  
 
     def natural_key(self):
 
     def natural_key(self):
         return (self.name,) + self.author.natural_key()</pre>
+
         return (self.name,) + self.author.natural_key()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The natural key for a <code>Book</code> is a combination of its name and its
+
<code>Book</code> 的自然键是其名称和作者的组合。 这意味着 <code>Person</code> 必须在 <code>Book</code> 之前序列化。 为了定义这个依赖,我们额外添加了一行:
author. This means that <code>Person</code> must be serialized before <code>Book</code>.
 
To define this dependency, we add one extra line:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第849行: 第711行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def natural_key(self):
+
<syntaxhighlight lang="python">def natural_key(self):
 
     return (self.name,) + self.author.natural_key()
 
     return (self.name,) + self.author.natural_key()
natural_key.dependencies = ['example_app.person']</pre>
+
natural_key.dependencies = ['example_app.person']</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This definition ensures that all <code>Person</code> objects are serialized before
+
此定义确保所有 <code>Person</code> 对象在任何 <code>Book</code> 对象之前序列化。 反过来,在 <code>Person</code> <code>Book</code> 都被序列化之后,任何引用 <code>Book</code> 的对象都将被序列化。
any <code>Book</code> objects. In turn, any object referencing <code>Book</code> will be
+
 
serialized after both <code>Person</code> and <code>Book</code> have been serialized.
 
  
 +
</div>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
 +
<div class="clearer">
 +
 +
  
 
</div>
 
</div>
  
[[Category:Django 2.2.x 中文文档]]
+
[[Category:Django 2.2.x 文档]]

2021年10月31日 (日) 04:08的最新版本

序列化 Django 对象

Django 的序列化框架提供了一种将 Django 模型“翻译”成其他格式的机制。 通常这些其他格式将基于文本并用于通过线路发送 Django 数据,但序列化程序可以处理任何格式(基于文本或非文本)。

也可以看看

如果你只是想从你的表中获取一些数据到序列化的形式,你可以使用 :djadmin:`dumpdata` 管理命令。


序列化数据

在最高级别,序列化数据是一个非常简单的操作:

from django.core import serializers
data = serializers.serialize("xml", SomeModel.objects.all())

serialize 函数的参数是将数据序列化为的格式(请参阅 序列化格式 )和要序列化的 QuerySet。 (实际上,第二个参数可以是任何生成 Django 模型实例的迭代器,但它几乎总是一个 QuerySet)。

django.core.serializers.get_serializer(format)

您还可以直接使用序列化程序对象:

XMLSerializer = serializers.get_serializer("xml")
xml_serializer = XMLSerializer()
xml_serializer.serialize(queryset)
data = xml_serializer.getvalue()

如果您想将数据直接序列化为类似文件的对象(包括 HttpResponse),这将非常有用:

with open("file.xml", "w") as out:
    xml_serializer.serialize(SomeModel.objects.all(), stream=out)

笔记

使用未知的 格式 调用 get_serializer() 将引发 django.core.serializers.SerializerDoesNotExist 异常。


字段子集

如果您只想序列化字段的子集,则可以为序列化程序指定 fields 参数:

from django.core import serializers
data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))

在本例中,只会序列化每个模型的 namesize 属性。 主键始终序列化为结果输出中的 pk 元素; 它从未出现在 fields 部分。

笔记

根据您的模型,您可能会发现无法反序列化仅序列化其字段子集的模型。 如果序列化对象没有指定模型所需的所有字段,反序列化器将无法保存反序列化实例。


继承模型

如果您有一个使用 抽象基类 定义的模型,则无需执行任何特殊操作即可序列化该模型。 只需在要序列化的对象(或多个对象)上调用序列化程序,输出将是序列化对象的完整表示。

但是,如果您有一个使用 多表继承 的模型,您还需要序列化该模型的所有基类。 这是因为只有在模型上本地定义的字段才会被序列化。 例如,考虑以下模型:

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)

如果您只序列化 Restaurant 模型:

data = serializers.serialize('xml', Restaurant.objects.all())

序列化输出上的字段将仅包含 serves_hot_dogs 属性。 基类的 name 属性将被忽略。

为了完全序列化您的 Restaurant 实例,您还需要序列化 Place 模型:

all_objects = [*Restaurant.objects.all(), *Place.objects.all()]
data = serializers.serialize('xml', all_objects)

反序列化数据

反序列化数据也是一个相当简单的操作:

for obj in serializers.deserialize("xml", data):
    do_something_with(obj)

如您所见,deserialize 函数采用与 serialize 相同的格式参数,一个字符串或数据流,并返回一个迭代器。

然而,这里有点复杂。 deserialize 迭代器 返回的对象不是 简单的 Django 对象。 相反,它们是特殊的 DeserializedObject 实例,用于包装已创建但未保存的对象和任何关联的关系数据。

调用 DeserializedObject.save() 将对象保存到数据库中。

笔记

如果序列化数据中的 pk 属性不存在或为空,则将新实例保存到数据库中。


这确保了反序列化是一种非破坏性操作,即使序列化表示中的数据与数据库中当前的数据不匹配。 通常,使用这些 DeserializedObject 实例看起来像:

for deserialized_object in serializers.deserialize("xml", data):
    if object_should_be_saved(deserialized_object):
        deserialized_object.save()

换句话说,通常的用途是检查反序列化的对象,以确保它们在执行之前“适合”保存。 当然,如果您信任您的数据源,您可以保存对象并继续。

Django 对象本身可以被检查为 deserialized_object.object。 如果序列化数据中的字段在模型上不存在,除非将 ignorenonexistent 参数作为 True 传入,否则将引发 DeserializationError

serializers.deserialize("xml", data, ignorenonexistent=True)

序列化格式

Django 支持多种序列化格式,其中一些需要您安装第三方 Python 模块:

标识符 信息
xml 与简单的 XML 方言之间进行序列化。
json JSON 之间的序列化。
yaml 序列化为 YAML(YAML 不是标记语言)。 此序列化程序仅在安装了 PyYAML 时可用。

XML

基本的 XML 序列化格式非常简单:

<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
    <object pk="123" model="sessions.session">
        <field type="DateTimeField" name="expire_date">2013-01-16T08:16:59.844560+00:00</field>
        <!-- ... -->
    </object>
</django-objects>

序列化或反序列化的整个对象集合由包含多个 <object> 元素的 <django-objects> 标签表示。 每个这样的对象都有两个属性:“pk”和“model”,后者由应用程序的名称(“sessions”)和模型的小写名称(“session”)表示,中间用点分隔。

对象的每个字段都被序列化为一个 <field> 元素,其中包含字段“类型”和“名称”。 元素的文本内容表示应该存储的值。

外键和其他关系字段的处理方式略有不同:

<object pk="27" model="auth.permission">
    <!-- ... -->
    <field to="contenttypes.contenttype" name="content_type" rel="ManyToOneRel">9</field>
    <!-- ... -->
</object>

在此示例中,我们指定具有 PK 27 的 auth.Permission 对象具有指向具有 PK 9 的 contenttypes.ContentType 实例的外键。

为绑定它们的模型导出多对多关系。 例如,auth.User 模型与 auth.Permission 模型有这样的关系:

<object pk="1" model="auth.user">
    <!-- ... -->
    <field to="auth.permission" name="user_permissions" rel="ManyToManyRel">
        <object pk="46"></object>
        <object pk="47"></object>
    </field>
</object>

此示例将给定用户与具有 PK 46 和 47 的权限模型相关联。

控制字符

如果要序列化的内容包含 XML 1.0 标准中不接受的控制字符,则序列化将失败并出现 ValueError 异常。 另请阅读 W3C 对 HTML、XHTML、XML 和控制代码 的解释。


JSON

当使用与之前相同的示例数据时,它将按以下方式序列化为 JSON:

[
    {
        "pk": "4b678b301dfd8a4e0dad910de3ae245b",
        "model": "sessions.session",
        "fields": {
            "expire_date": "2013-01-16T08:16:59.844Z",
            ...
        }
    }
]

此处的格式设置比 XML 简单一些。 整个集合仅表示为一个数组,对象由具有三个属性的 JSON 对象表示:“pk”、“model”和“fields”。 “fields”也是一个对象,分别包含每个字段的名称和值作为属性和属性值。

外键只是将链接对象的 PK 作为属性值。 ManyToMany 关系针对定义它们的模型进行序列化,并表示为 PK 列表。

请注意,并非所有 Django 输出都可以不加修改地传递给 json。 例如,如果要序列化的对象中有一些自定义类型,则必须为其编写自定义 json 编码器。 像这样的事情会起作用:

from django.core.serializers.json import DjangoJSONEncoder

class LazyEncoder(DjangoJSONEncoder):
    def default(self, obj):
        if isinstance(obj, YourCustomType):
            return str(obj)
        return super().default(obj)

然后,您可以将 cls=LazyEncoder 传递给 serializers.serialize() 函数:

from django.core.serializers import serialize

serialize('json', SomeModel.objects.all(), cls=LazyEncoder)

另请注意,GeoDjango 提供了 自定义 GeoJSON 序列化程序

DjangoJSONEncoder

class django.core.serializers.json.DjangoJSONEncoder

JSON 序列化程序使用 DjangoJSONEncoder 进行编码。 JSONEncoder 的子类,它处理这些附加类型:

datetime
ECMA-262 中定义的 YYYY-MM-DDTHH:mm:ss.sssZYYYY-MM-DDTHH:mm:ss.sss+HH:MM 形式的字符串。
date
ECMA-262 中定义的 YYYY-MM-DD 形式的字符串。
time
ECMA-262 中定义的 HH:MM:ss.sss 形式的字符串。
timedelta
表示 ISO-8601 中定义的持续时间的字符串。 例如,timedelta(days=1, hours=2, seconds=3.4) 表示为 'P1DT02H00M03.400000S'
DecimalPromisedjango.utils.functional.lazy() 对象)、UUID
对象的字符串表示形式。


YAML

YAML 序列化看起来与 JSON 非常相似。 对象列表被序列化为具有键“pk”、“模型”和“字段”的序列映射。 每个字段又是一个映射,键是字段名,值是值:

-   fields: {expire_date: !!timestamp '2013-01-16 08:16:59.844560+00:00'}
    model: sessions.session
    pk: 4b678b301dfd8a4e0dad910de3ae245b

引用字段再次仅由 PK 或 PK 序列表示。


自然键

外键和多对多关系的默认序列化策略是序列化关系中对象的主键的值。 此策略适用于大多数对象,但在某些情况下可能会造成困难。

考虑具有引用 ContentType 的外键的对象列表的情况。 如果您要序列化引用内容类型的对象,那么您需要有一种方法来引用该内容类型。 由于 ContentType 对象是 Django 在数据库同步过程中自动创建的,给定内容类型的主键不容易预测; 这将取决于 :djadmin:`migrate` 的执行方式和时间。 这适用于所有自动生成对象的模型,特别是包括 PermissionGroupUser

警告

您永远不应该在夹具或其他序列化数据中包含自动生成的对象。 偶然地,夹具中的主键可能与数据库中的主键匹配,并且加载夹具将不起作用。 在更可能的情况下,它们不匹配,夹具加载将失败并显示 IntegrityError


还有一个方便的问题。 整数 id 并不总是引用对象的最方便的方式; 有时,更自然的参考会有所帮助。

正是出于这些原因,Django 提供了 自然键 。 自然键是一组值,可用于在不使用主键值的情况下唯一标识对象实例。

自然键的反序列化

考虑以下两个模型:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    birthdate = models.DateField()

    class Meta:
        unique_together = [[../'first_name', 'last_name']]

class Book(models.Model):
    name = models.CharField(max_length=100)
    author = models.ForeignKey(Person, on_delete=models.CASCADE)

通常,Book 的序列化数据将使用整数来指代作者。 例如,在 JSON 中,一本书可能被序列化为:

...
{
    "pk": 1,
    "model": "store.book",
    "fields": {
        "name": "Mostly Harmless",
        "author": 42
    }
}
...

这不是指代作者的一种特别自然的方式。 它要求您知道作者的主键值; 它还要求这个主键值是稳定的和可预测的。

但是,如果我们为 Person 添加自然键处理,则装置变得更加人性化。 要添加自然键处理,您可以使用 get_by_natural_key() 方法为 Person 定义一个默认管理器。 在 Person 的情况下,一个好的自然键可能是一对名字和姓氏:

from django.db import models

class PersonManager(models.Manager):
    def get_by_natural_key(self, first_name, last_name):
        return self.get(first_name=first_name, last_name=last_name)

class Person(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    birthdate = models.DateField()

    objects = PersonManager()

    class Meta:
        unique_together = [[../'first_name', 'last_name']]

现在书籍可以使用该自然键来引用 Person 对象:

...
{
    "pk": 1,
    "model": "store.book",
    "fields": {
        "name": "Mostly Harmless",
        "author": ["Douglas", "Adams"]
    }
}
...

当您尝试加载这个序列化数据时,Django 将使用 get_by_natural_key() 方法将 ["Douglas", "Adams"] 解析为实际 Person 对象的主键。

笔记

用于自然键的任何字段都必须能够唯一标识一个对象。 这通常意味着您的模型将为您的自然键中的一个或多个字段提供一个唯一性子句(在单个字段上使用 unique=True,或者在多个字段上使用 unique_together)。 但是,不需要在数据库级别强制执行唯一性。 如果您确定一组字段实际上是唯一的,您仍然可以将这些字段用作自然键。


没有主键的对象的反序列化将始终检查模型的管理器是否有 get_by_natural_key() 方法,如果有,使用它来填充反序列化对象的主键。


自然键的序列化

那么如何让 Django 在序列化对象时发出自然键呢? 首先,您需要添加另一个方法——这次是添加到模型本身:

class Person(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    birthdate = models.DateField()

    objects = PersonManager()

    class Meta:
        unique_together = [[../'first_name', 'last_name']]

    def natural_key(self):
        return (self.first_name, self.last_name)

该方法应该总是返回一个自然键元组——在这个例子中,(first name, last name)。 然后,当您调用 serializers.serialize() 时,您提供 use_natural_foreign_keys=Trueuse_natural_primary_keys=True 参数:

>>> serializers.serialize('json', [book1, book2], indent=2,
...      use_natural_foreign_keys=True, use_natural_primary_keys=True)

当指定 use_natural_foreign_keys=True 时,Django 将使用 natural_key() 方法将任何外键引用序列化到定义该方法的类型的对象。

当指定 use_natural_primary_keys=True 时,Django 不会在此对象的序列化数据中提供主键,因为它可以在反序列化过程中计算:

...
{
    "model": "store.person",
    "fields": {
        "first_name": "Douglas",
        "last_name": "Adams",
        "birth_date": "1952-03-11",
    }
}
...

当您需要将序列化数据加载到现有数据库中并且您不能保证序列化主键值尚未被使用,并且不需要确保反序列化对象保留相同的主键时,这会很有用。

如果您使用 :djadmin:`dumpdata` 生成序列化数据,请使用 dumpdata --natural-foreigndumpdata --natural-primary 命令行标志生成自然键。

笔记

您不需要同时定义 natural_key()get_by_natural_key()。 如果你不希望 Django 在序列化过程中输出自然键,但又想保留加载自然键的能力,那么你可以选择不实现 natural_key() 方法。

相反,如果(出于某种奇怪的原因)您希望 Django 在序列化期间输出自然键,但 not 能够加载这些键值,只需不要定义 get_by_natural_key() 方法。


自然键和前向引用

2.2 版中的新功能。


有时,当您使用 自然外键 时,您需要反序列化数据,其中一个对象的外键引用了另一个尚未反序列化的对象。 这称为“前向参考”。

例如,假设您的夹具中有以下对象:

...
{
    "model": "store.book",
    "fields": {
        "name": "Mostly Harmless",
        "author": ["Douglas", "Adams"]
    }
},
...
{
    "model": "store.person",
    "fields": {
        "first_name": "Douglas",
        "last_name": "Adams"
    }
},
...

为了处理这种情况,您需要将 handle_forward_references=True 传递给 serializers.deserialize()。 这将在 DeserializedObject 实例上设置 deferred_fields 属性。 您需要跟踪此属性不是 NoneDeserializedObject 实例,然后在它们上调用 save_deferred_fields()

典型用法如下所示:

objs_with_deferred_fields = []

for obj in serializers.deserialize('xml', data, handle_forward_references=True):
    obj.save()
    if obj.deferred_fields is not None:
        objs_with_deferred_fields.append(obj)

for obj in objs_with_deferred_fields:
    obj.save_deferred_fields()

为此,参考模型上的 ForeignKey 必须具有 null=True


序列化期间的依赖

通常可以通过注意夹具内对象的顺序来避免显式处理前向引用。

为了解决这个问题,使用 dumpdata --natural-foreign 选项调用 :djadmin:`dumpdata` 将在序列化标准主键对象之前使用 natural_key() 方法序列化任何模型。

然而,这可能并不总是足够的。 如果您的自然键引用另一个对象(通过使用另一个对象的外键或自然键作为自然键的一部分),那么您需要能够确保自然键所依赖的对象出现在序列化数据中在自然键需要它们之前。

要控制此顺序,您可以定义对 natural_key() 方法的依赖关系。 您可以通过在 natural_key() 方法本身上设置 dependencies 属性来完成此操作。

例如,让我们为上面示例中的 Book 模型添加一个自然键:

class Book(models.Model):
    name = models.CharField(max_length=100)
    author = models.ForeignKey(Person, on_delete=models.CASCADE)

    def natural_key(self):
        return (self.name,) + self.author.natural_key()

Book 的自然键是其名称和作者的组合。 这意味着 Person 必须在 Book 之前序列化。 为了定义这个依赖,我们额外添加了一行:

def natural_key(self):
    return (self.name,) + self.author.natural_key()
natural_key.dependencies = ['example_app.person']

此定义确保所有 Person 对象在任何 Book 对象之前序列化。 反过来,在 PersonBook 都被序列化之后,任何引用 Book 的对象都将被序列化。