序列化Django对象

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

也可以看看

如果您只想从表中获取一些数据以序列化的形式,则可以使用dumpdata管理命令。

序列化数据

在最高级别,您可以像这样序列化数据:

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

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

django.core.serializers.get_serializer格式

您也可以直接使用序列化器对象:

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)

如果仅序列化餐厅模型:

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函数采用与相同的format参数 serialize,一个字符串或数据流,并返回一个迭代器。

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

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

注意

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

这样可以确保反序列化是一种无损操作,即使序列化表示中的数据与数据库中当前的数据不匹配也是如此。通常,使用这些DeserializedObject实例看起来像:

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

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

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

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>

被序列化或反序列化的对象的整个集合由<django-objects>包含多个<object>-elements 的-tag 表示。每个此类对象都具有两个属性:“ pk”和“模型”,后者由应用程序名称(“会话”)表示,模型的小写名称(“会话”)用点分隔。

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

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

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

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

会为绑定它们的模型导出ManyToMany-relations。例如,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-relations对于定义它们的模型进行了序列化,并表示为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=LazyEncoderserializers.serialize() 函数:

from django.core.serializers import serialize

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

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

在Django 3.1中进行了更改:

现在,所有数据都使用Unicode转储。如果您需要以前的行为,请传递ensure_ascii=True给该serializers.serialize()函数。

DjangoJSONEncoder

django.core.serializers.json.DjangoJSONEncoder

JSON序列化程序DjangoJSONEncoder用于编码。的子类 JSONEncoder,它处理以下其他类型:

datetime
形式YYYY-MM-DDTHH:mm:ss.sssZ或 YYYY-MM-DDTHH:mm:ss.sss+HH:MMECMA-262中所定义的字符串。
date
格式YYYY-MM-DDECMA-262的字符串。
time
格式HH:MM:ss.sssECMA-262的字符串。
timedelta
代表ISO-8601中定义的持续时间的字符串。例如, 表示为 。timedelta(days=1, hours=2, seconds=3.4)'P1DT02H00M03.400000S'
DecimalPromise(个django.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序列表示。

在Django 3.1中进行了更改:

现在,所有数据都使用Unicode转储。如果您需要以前的行为,请传递allow_unicode=False给该serializers.serialize()函数。

自然键

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

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

警告

绝对不要在灯具或其他序列化数据中包含自动生成的对象。偶然地,灯具中的主键可能与数据库中的主键匹配,并且加载灯具将无效。如果它们不匹配的可能性更大,则夹具加载将失败,并带有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添加自然键处理,则固定装置将变得更加人性化。要添加自然键处理,请使用方法定义默认的Person Manager get_by_natural_key()。对于个人,一个好的自然键可能是名字和姓氏对:

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_together您的自然键中的一个或多个字段具有唯一性子句(在单个字段或多个字段上为unique = True )。但是,不需要在数据库级别强制执行唯一性。如果确定一组字段实际上是唯一的,则仍可以将这些字段用作自然键。

没有主键的对象的反序列化将始终检查模型管理器是否具有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",
}
}
...

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

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

注意

您无需同时定义natural_key()和 get_by_natural_key()。如果您不希望Django在序列化期间输出自然键,而是希望保留加载自然键的功能,则可以选择不实现该natural_key()方法。

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

自然键和向前引用

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

例如,假设您的灯具中包含以下对象:

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

为了处理这种情况,您需要传递 handle_forward_references=Trueserializers.deserialize()。这将deferred_fieldsDeserializedObject实例上设置属性。您需要跟踪DeserializedObject没有该属性的实例,None然后再调用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使用该选项的调用将 在序列化标准主键对象之前使用方法序列化任何模型。dumpdata --natural-foreignnatural_key()

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

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

例如,让我们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()

a的自然键Book是其名称和作者的组合。这意味着Person必须先序列化Book。为了定义这种依赖性,我们增加了一行:

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

此定义确保所有Person对象在任何Book对象之前先序列化。反过来,任何对象引用Book都将经过序列化Person,并Book已系列化。

django 3.1 序列化讲述的更多相关文章

  1. Django 缓存、序列化、信号

    一,缓存 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcac ...

  2. Django框架之序列化和上传文件

     一.Django的序列化(对于ajax请求) Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式. 1)django序列化的使用方法 . ...

  3. django rest_framework Serializers 序列化组件

    为什么要用序列化组件 当我们做前后端分离的项目~~我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿 ...

  4. Django的DRF序列化方法

    安装rest_framework -- pip install djangorestframework -- 注册rest_framework序列化 -- Python--json -- 第一版 用v ...

  5. JSON和Django内置序列化

    JSON 什么是JSON JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JSON 独立于语言 * J ...

  6. Django REST Framework序列化器

    Django序列化和json模块的序列化 从数据库中取出数据后,虽然不能直接将queryset和model对象以及datetime类型序列化,但都可以将其转化成可以序列化的类型,再序列化. 功能需求都 ...

  7. AJAX—JSON和Django内置序列化

    JSON 什么是JSON JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JSON 独立于语言 * J ...

  8. Django学习之序列化和信号

    一.序列化 1.serializers 2.json.dumps 二.信号 1.Django内置信号 2.自定义信号 一.序列化 关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用 ...

  9. [Django REST framework - 序列化组件、source、钩子函数]

    [Django REST framework - 序列化组件.source.钩子函数] 序列化器-Serializer 什么是rest_framework序列化? 在写前后端不分离的项目时: 我们有f ...

随机推荐

  1. 区块链入门到实战(24)之以太坊(Ethereum) – 网络节点

    用途: 全节点:用于区块和交易的校验 轻节点:电子钱包 以太坊(Ethereum)网络是一个公共的区块链网络,网络中包含2种网络节点: 全节点 轻节点 全节点 包含了从初始区块开始的全部区块,这些区块 ...

  2. 通过Tomcat jpress连接不到数据库

    -- 实际数据库.用户名,密码,主机账号,端口号均正确 提示如下: 异常如下:------------------------------------------------------------- ...

  3. oeasy教您玩转linux010202软件包管理apt

    顾一下 上一部分我们都讲了什么?

  4. 填坑 | .NET core项目远程部署后连接数据库 mysql表大小写敏感问题

    欣喜成功部署了项目之后又遭遇重创hhh,swagger调试数据库,报错 MySql.Data.MySqlClient.MySqlException(0x80004005) 我猜是大小写的问题,一查果然 ...

  5. 支付-微信h5

    背景 h5支付分两种 1.浏览器 2.app 浏览器里的h5,最终也会跳转到app. 而app里的h5,本质是公众号.在微信里叫公众号,支付宝叫服务窗. 这里主要讲微信h5. 核心原理 最终目标是下单 ...

  6. 网址中的静态资源 public

     客户端浏览器收到的HTML响应内容中如果带有 link img script video audio 等带有src或者href标签时候,这些都是外部链接资源请求url.浏览器会默认自动性的对这些资源 ...

  7. Linux服务器被入侵后的处理过程

    突然,频繁收到一组服务器 ping 监控不可达邮件,赶紧登陆 zabbix 监控系统查看流量状况. 可见流量已经达到了 800M 左右,这肯定不正常了,马上尝试 SSH 登陆系统,不幸的事,由于网络堵 ...

  8. Zabbix 5.0切换中文语言小结

    最近测试Zabbix 5.0,去修改语言时发现不能选择"Chinese(zh_CN)",这个选项在下拉框中是灰色的(无法选择).提示"You are not able t ...

  9. leetcode刷题-95/96/98

    题目95题 给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树 . 示例: 输入:3输出:[  [1,null,3,2],  [3,2,null,1],  [3,1,null,n ...

  10. 【漫话DevOps】Agile,CI/CD,DevOps

    随着DevOps理念的普及与扩散,可能会被一大堆名字概念搞的莫名其妙,理清它们之间的关系可以帮助团队知道DevOps如何落地,改善工作流程. Here's a quick and easy way t ...