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