Serialize----序列化django對象

django的序列化框架提供了一個把django對象轉換成其餘格式的機制,一般這些其餘的格式都是基於文本的而且用於經過一個管道發送django對象,但一個序列器是可能處理任何一個格式的(基於文本或者不是)數據庫

django的序列化類位於django.core下面的serializers文件夾裏面,base.py文件裏面定義了序列器和反序列器的基類以及一些異常,__init__.py文件定義瞭如何根據格式來選擇對應的序列器等內容,咱們一塊兒來看看吧django

__init__.py和base.py文件的函數原型以下圖json

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()
 

 
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):

 

 

那下面咱們開始正式講解django的序列化操做了api

序列化數據

在最高層的api,序列化數據是很是容易的操做,看上面的函數可知,serialize函數接受一個格式和queryset,返回序列化後的數據:app

簡單的寫法:框架

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

 

複雜的寫法:less

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()方法把這些數據保存到數據庫post

序列化格式

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)
相關文章
相關標籤/搜索