1. 程式人生 > >django序列化 serializers

django序列化 serializers

Django的序列化工具讓你可以將Django的模型‘翻譯’成其它格式的資料。通常情況下,這種其它格式的資料是基於文字的,並且用於資料交換\傳輸過程。

一、序列化資料

Django為我們提供了一個強大的序列化工具serializers。使用它也很簡單,如下所示:

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

首先,從djang.core匯入它,然後呼叫它的serialize方法,這個方法至少接收兩個引數,第一個是你要序列化成為的資料格式,這裡是‘xml’,第二個是要序列化的資料物件,資料通常是ORM模型的QuerySet,一個可迭代的物件。

就是這麼簡單!!

還有一種比較複雜,但鉤子更多的使用方法,如下所示:

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

主要是使用了serializers的get_serializer()和getvalue()方法。

當你需要將序列化的資料儲存到一個檔案物件中的時候,上面的方式就非常有用,例如:

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

1. 序列化指定欄位

如果你不想序列化模型物件所有欄位的內容,只想序列化某些指定的欄位,可以使用fields引數,如下所示:

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

這樣,只有name和size欄位會被序列化。但是,有一個例外,模型的主鍵pk被隱式輸出了,雖然它並不包含在fields引數中。

2. 序列化繼承模型

考慮下面的模型繼承:

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 = list(Restaurant.objects.all()) + list(Place.objects.all())
data = serializers.serialize('xml', all_objects)

二、反序列化資料

反序列化也相當簡單,如下所示:

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

其中的data是我們以前序列化後生成的資料(一個字串或者資料流)。deserialize()方法返回的是一個迭代器,通過for迴圈,拿到它內部的每個元素。

在這裡有區別的是,deserialize返回的迭代器物件不是簡單的Django模型的物件。而是特殊的DeserializedObject例項。呼叫DeserializedObject.save()方法可以將物件儲存到資料庫。

PS:如果序列化資料中的pk屬性不存在或為null,則新例項將儲存到資料庫。

將DeserializedObject儲存到資料庫,可以如下操作:

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

在這麼做之前,你必須保證你的序列化資料是合乎你本地ORM模型屬性的,否則儲存的過程中會出現各種讓你撓頭的錯誤,這是很顯然的。

三、可序列化的格式

Djanggo支援三種序列化格式,其中的一些可能需要安裝第三方庫支援:

  • xml
  • json
  • yaml

1. 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 pk="27" model="auth.permission"> <!-- ... --> <field to="contenttypes.contenttype" name="content_type" rel="ManyToOneRel">9</field> <!-- ... --> </object> 

多對多欄位被序列化成下面的樣子:

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

2. JSON

序列化成json格式後,看起來是下面的樣子:

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

需要注意的是,如果你的ORM模型具有自定義的欄位,那麼Django給我們提供的序列化工具,就無法正常工作,你必須自己編寫相應部分的序列化程式碼,下面是一個參考的例子:

from django.utils.encoding import force_text
from django.core.serializers.json import DjangoJSONEncoder class LazyEncoder(DjangoJSONEncoder): def default(self, obj): if isinstance(obj, YourCustomType): return force_text(obj) return super(LazyEncoder, self).default(obj) 

上面編寫了一個LazyEncoder類,用來實現你的序列化方法,使用下面的方法呼叫它:

from django.core.serializers import serialize

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

PS:Python本身不支援序列化到json格式,Django幫我們實現了它自己的模型類序列化為json的方法,但也僅限於此,如果你在Django內寫了一個別的自定義類,一樣無法序列化為json格式,除非你自己實現,像上面的例子所示。

3. YAML

yaml的格式和json很像,如下所示:

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