django的序列化框架提供了一个把django对象转换成其他格式的机制,通常这些其他的格式都是基于文本的并且用于通过一个管道发送django对象,但一个序列器是可能处理任何一个格式的(基于文本或者不是)

django的序列化类位于django.core下面的serializers文件夹里面,base.py文件里面定义了序列器和反序列器的基类以及一些异常,__init__.py文件定义了如何根据格式来选择对应的序列器等内容,我们一起来看看吧

__init__.py和base.py文件的函数原型如下图

def serialize(format, queryset, **options):
"""Serialize a queryset (or any iterator that returns database objects) using
a certain serializer."""
s = get_serializer(format)()
s.serialize(queryset, **options)
return s.getvalue()

def deserialize(format, stream_or_string, **options):
""" Deserialize a stream or a string. Returns an iterator that yields ``(obj,
m2m_relation_dict)``, where ``obj`` is a instantiated -- but *unsaved* --
object, and ``m2m_relation_dict`` is a dictionary of ``{m2m_field_name :
list_of_related_objects}``. """
d = get_deserializer(format)
return d(stream_or_string, **options)
class Serializer(object):
""" Abstract serializer base class. """
# Indicates if the implemented serializer is only available for
# internal Django use.
internal_use_only = False
def serialize(self, queryset, **options):

class Deserializer(object):
""" Abstract base deserializer class. """ def __init__(self, stream_or_string, **options):

那下面我们开始正式讲解django的序列化操作了

序列化数据

在最高层的api,序列化数据是非常容易的操作,看上面的函数可知,serialize函数接受一个格式和queryset,返回序列化后的数据:

简单的写法:

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

复杂的写法:

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

解序列化数据

一样的简单,接受一个格式和一个数据流,返回一个迭代器

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

然而,deserialize返回的的是不是简单的django类型对象,而是DeserializedObject实例,并且这些实例是没有保存的,请使用DeserializedObject.save()方法把这些数据保存到数据库

序列化格式

django之处很多的序列化格式,有些需要你安装第三方支持的模块,xml,json和yaml是默认支持的

注意事项

如果你是使用utf-8或者其他的非ascii编码数据,然后用json序列器,注意穿一个ensure_ascii参数进去,否则输出的编码将会不正常

json_serializer = serializers.get_serializer("json")()
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)

序列化参数

序列化的是是可以接受额外的参数的,总共有三个参数,如下:

        self.stream = options.pop("stream", StringIO())
self.selected_fields = options.pop("fields", None)
self.use_natural_keys = options.pop("use_natural_keys", False)

stream

将序列化后的数据输出到该stream流中,接上面的复杂的写法:

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

selected_field

选择序列化的属性,通过制定fields参数,fields是一个元组参数,元素是选择要序列化的属性

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

use_natural_keys

是否使用自然的关键字,默认是false(即是使用主键)

默认的外键和多对多关系序列化策略是使用主键,一般情况下是很好地,但有些情况下就不是这样了。比如外键到ContentType的时候,由于ContentType是django的数据库进程同步的时候自动产生的,它们的关键字不是那么容易去预测的。

一个整数id也不总是最方便的索引到一个对象的方法,所以基于这些情况,django提供了use_natural_keys这个参数,

一个natural key是一个可以不使用主键就可以用来区分一个元素的属性组合的元组

natural keys的解序列化

考虑这两个模型

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)

默认Book 的序列化数据将会使用一个整数索引到一个作者,例如,用json的是,一个Book的序列化数据大概是这样的,42是外键Author的主键

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

但这不是一个很好的方法,不是吗?你需要知道这个主键代表到底是哪个Author,并且要求这个主键是稳定和可预测的。所以,我们可以增加一个natural key的处理函数,请在对应模型的管理模型里面定义一个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):
objects = PersonManager()
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'),)

这样之后,序列化的结果大概是这样的:

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

natural keys的序列化

如果你想在序列化的时候使用natural key,那你必须在被序列化的模型里面顶一个natural_key方法,并在序列化的时候使用use_natural_keys=True属性如下:

class Person(models.Model):
objects = PersonManager()
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
birthdate = models.DateField()
def natural_key(self):
return (self.first_name, self.last_name)
class Meta:
unique_together = (('first_name', 'last_name'),)
serializers.serialize('json', [book1, book2], use_natural_keys=True)

注意:natural_key()和get_by_natural_key()不是同时定义的,如果你只想重载natural keys的能力,那么你不必定义natural_key()方法;同样,如果你只想在序列化的时候输出这些natural keys,那么你不必定义get_by_natural_key()方法

序列化过程中的依赖关系

因为natural keys依赖数据库查询来解析引用,所以在数据被引用之前必须确保数据是存在的。看下面的例子,如果一个Book的natural key是书名和作者的组合,你可以这样写:

class Book(models.Model):
name = models.CharField(max_length=100)
author = models.ForeignKey(Person) def natural_key(self):
return (self.name,) + self.author.natural_key()

那么问题来了,如果Author还没有被序列化呢?很明显,Author应该在Book之前被序列化,为此,我们可以添加一个依赖关系如下:

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

这保证了Person对象是在Book对象之前被序列化的,同样,任何一个引用Book的对象只有在Person和Book对象都被序列化之后才会被序列化

继承的模型

如果是使用抽象继承的时候,不必在意这个问题;如果你使用的是多表继承,那么注意了:必须序列化所有的基类,例如:

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

如果仅仅序列化Restaurant模型,那么只会得到一个serves_hot_dog属性,基类的属性将被忽略,你必须同时序列化所有的继承的模型,如下:

all_objects = list(Restaurant.objects.all()) + list(Place.objects.all())
data = serializers.serialize('xml', all_objects)

21:序列化django对象的更多相关文章

  1. 写写Django中DRF框架概述以及序列化器对象serializer的构造方法以及使用

    写写Django中DRF框架概述以及序列化器对象serializer的构造方法以及使用 一.了解什么是DRF DRF: Django REST framework Django REST framew ...

  2. Serialize----序列化django对象

    django的序列化框架提供了一个把django对象转换成其他格式的机制,通常这些其他的格式都是基于文本的并且用于通过一个管道发送django对象,但一个序列器是可能处理任何一个格式的(基于文本或者不 ...

  3. PHP的序列化、对象、反射、异常与错误

    1. 怎么理解php里面的序列化与反序列化? 序列化是将对象转换为字节流.反序列化就是将流转换为对象. 这两个过程结合起来,可以轻松地存储和传输数据,在网络中可以做到跨平台.快速传输. 两种序列化方式 ...

  4. 零基础学习java------day17------缓冲字节流,转换字节流,简化流,缓冲字符流,序列化和对象流

    1. 缓冲字节流 缓冲区:缓冲区实质上是一个数组.通常它是一个字节数组,但是也可以使用其他种类的数组.但是一个缓冲区不 仅仅 是一个数组.缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程 ...

  5. java提高篇(六)-----使用序列化实现对象的拷贝

    我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常 ...

  6. .NET调用外部接口将得到的List数据,并使用XmlSerializer序列化List对象成XML格式

    BidOpeningData.BidSupervisionSoapClient client = new BidOpeningData.BidSupervisionSoapClient(); Dict ...

  7. Activity之间传递数据或数据包Bundle,传递对象,对象序列化,对象实现Parcelable接口

    package com.gaojinhua.android.activitymsg; import android.content.Intent; import android.os.Bundle; ...

  8. [改善Java代码] 推荐使用序列化实现对象的拷贝

    建议44: 推荐使用序列化实现对象的拷贝 上一个建议说了对象的浅拷贝问题,实现Cloneable接口就具备了拷贝能力,那我们来思考这样一个问题:如果一个项目中有大量的对象是通过拷贝生成的,那我们该如何 ...

  9. java提高篇(五)-----使用序列化实现对象的拷贝

          我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性 ...

随机推荐

  1. POJ2976:Dropping tests——题解

    http://poj.org/problem?id=2976 题目大意:给定n个二元组(a,b),从中取n-k个,使得100*∑a/∑b最大. 01分数规划裸题,设λ是小于等于最优解的,那么λ< ...

  2. BZOJ4355:Play with sequence——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4355 维护一个长度为N的序列a,现在有三种操作: 1)给出参数U,V,C,将a[U],a[U+1] ...

  3. BZOJ1008:[HNOI2008]越狱——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1008 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中 ...

  4. BZOJ1297:[SCOI2009]迷路——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1297 windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 ...

  5. mysql 读写分离,主从同步 理论

    mysql主从复制中:第一步:master记录二进制日志.在每个事务更新数据完成之前,master在二进制日志记录这些改变.MySQL将事务写入二进制日志,即使事务中的语句都是交叉执行的.在事件写入二 ...

  6. JNA的用法

    JNA(Java Native Access):建立在JNI之上的Java开源框架,SUN主导开发,用来调用C.C++代码,尤其是底层库文件(windows中叫dll文件,linux下是so[shar ...

  7. 如何让浏览器在访问链接时不要带上referer

    function open_without_referrer(link){ document.body.appendChild(document.createElement('iframe')).sr ...

  8. POJ1904:King's Quest(强连通+思维)

    King's Quest Time Limit: 15000MS   Memory Limit: 65536K Total Submissions: 10352   Accepted: 3815 题目 ...

  9. 【题解】Casting Spells LA 4975 UVa 1470 双倍回文 SDOI 2011 BZOJ 2342 Manacher

    首先要吐槽LRJ,书上给的算法标签是“有难度,需要结合其他数据结构”,学完Manacher才发现几乎一裸题 题目的意思是问原串中有多少个wwRwwR这样的子串,其中wR表示w的反串 比较容易看出来,w ...

  10. FreeRTOS - 程序开发阶段建议

    1.创建任务.定时器等都需要耗用分配给FreeRTOS的heap,由于RAM有限,分配作为FreeRTOS的heap量有限,一不小心就不够用了,所以应该有检测任务.定时器等是否创建成功,如下图: 2. ...