Serializer序列化器的定義與使用
序列化器的作用:
- 對資料進行校驗
- 對資料物件進行轉換(資料模型類和dict等資料間的轉換)
定義方法
Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。
例如,我們已有了一個數據庫模型類BookInfo
class BookInfo(models.Model): btitle = models.CharField(max_length=20, verbose_name='名稱') bpub_date = models.DateField(verbose_name='釋出日期', null=True) bread = models.IntegerField(default=0, verbose_name='閱讀量') bcomment = models.IntegerField(default=0, verbose_name='評論量') image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
我們想為這個模型類提供一個序列化器,可以定義如下:
class BookInfoSerializer(serializers.Serializer): """圖書資料序列化器""" id = serializers.IntegerField(label='ID', read_only=True) btitle = serializers.CharField(label='名稱', max_length=20) bpub_date = serializers.DateField(label='釋出日期', required=False) bread = serializers.IntegerField(label='閱讀量', required=False) bcomment = serializers.IntegerField(label='評論量', required=False) image = serializers.ImageField(label='圖片', required=False)
建立序列化器物件
定義好Serializer類後,就可以建立Serializer物件了。
Serializer的構造方法為:
Serializer(instance=None, data=empty, **kwarg)
1)用於序列化時,將模型類物件傳入instance引數
2)用於反序列化時,將要被反序列化的資料傳入data引數
3 ) 同時傳入instance引數和data引數,使用傳入的data資料對模型類物件例項進行修改
一:序列化
1:基本使用
還是以上面的圖書模型類資料為例
可在django shell中來簡單的使用序列化器來測試效果(注意修改資料模型類或序列化器等檔案後要重啟shell)
python manager.py shell
1) 先查詢出一個圖書物件
from booktest.models import BookInfo
book = BookInfo.objects.get(id=1)
2) 構造序列化器物件
from booktest.serializers import BookInfoSerializer
serializer = BookInfoSerializer(book)
3)獲取序列化資料
通過data屬性可以獲取序列化後的資料
serializer.data
4)如果要被序列化的是包含多條資料的查詢集QuerySet,可以通過新增many=True引數補充說明
book_qs = BookInfo.objects.all()
serializer = BookInfoSerializer(book_qs, many=True)
serializer.data
測試程式碼:
>>> from booktest.models import BookInfo
>>> from booktest.serializers import BookInfoSerializer
>>> book = BookInfo.objects.get(id=1)
>>> serializer = BookInfoSerializer(instance=book)
>>> serializer.data
{'btitle': '射鵰英雄傳', 'id': 1, 'bpub_date': '1980-05-01', 'bread': 12, 'bcomment': 34}
>>>
2.關聯物件巢狀序列化
如果需要序列化的資料中包含有其他關聯物件,則對關聯物件資料的序列化需要指明。
例如,在定義英雄資料的序列化器時,外來鍵hbook(即所屬的圖書)欄位如何序列化?
我們先定義HeroInfoSerialzier除外來鍵欄位外的其他部分
class HeroInfoSerializer(serializers.Serializer):
"""英雄資料序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
hname = serializers.CharField(label='名字', max_length=20)
hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性別', required=False)
hcomment = serializers.CharField(label='描述資訊', max_length=200, required=False, allow_null=True)
對於關聯欄位,可以採用以下幾種方式:
1) PrimaryKeyRelatedField : 此欄位將被序列化為關聯物件的主鍵。
hbook = serializers.PrimaryKeyRelatedField(label='圖書', read_only=True)
或
hbook = serializers.PrimaryKeyRelatedField(label='圖書', queryset=BookInfo.objects.all())
指明欄位時需要包含read_only=True或者queryset引數:
- 包含read_only=True引數時,該欄位將不能用作反序列化使用
- 包含queryset引數時,將被用作反序列化時引數校驗使用
使用效果:
from booktest.serializers import HeroInfoSerializer
from booktest.models import HeroInfo
hero = HeroInfo.objects.get(id=6)
serializer = HeroInfoSerializer(hero)
serializer.data
# {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': 2}
2) StringRelatedField
此欄位將被序列化為關聯物件的字串表示方式(即__str__方法的返回值)
hbook = serializers.StringRelatedField(label='圖書')
3)使用關聯物件的序列化器
hbook = BookInfoSerializer()
3. many引數
如果關聯的物件資料不是隻有一個,而是包含多個數據,如想序列化圖書BookInfo資料,每個BookInfo物件關聯的英雄HeroInfo物件可能有多個,此時關聯欄位型別的指明仍可使用上述幾種方式,只是在宣告關聯欄位時,多補充一個many=True引數即可。
此處僅拿PrimaryKeyRelatedField型別來舉例,其他相同。
在BookInfoSerializer中新增關聯欄位:
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='釋出日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
使用效果:
使用效果:
from booktest.serializers import BookInfoSerializer
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
# {'id': 2, 'btitle': '天龍八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None, 'heroinfo_set': [6,8, 9]}
二:反序列化
1.驗證
使用序列化器進行反序列化時,需要對資料進行驗證後,才能獲取驗證成功的資料或儲存成模型類物件。
在獲取反序列化的資料前,必須呼叫is_valid()方法進行驗證,驗證成功返回True,否則返回False
驗證的方式:
0.型別+選項:----------------------------------------及定義序列化器時,序列化器欄位本身型別和選項提供的驗證
1.validate_屬性名稱(self,value):---------------驗證指定的屬性值是否合法
# 對某個屬性欄位進行補充驗證
def validate_btitle(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError('圖書不是關於django的')
return value
2.validate(self,values):---------------------------驗證多個屬性
# 多個欄位之間的比較驗證
def validate(self, attrs):
bread = attrs.get('bread')
bcomment = attrs.get('bcomment')
if all ([bread, bcomment]):
if bread < bcomment:
raise serializers.ValidationError('閱讀量不能小於評論量')
return attrs
3.validators=[方法]:--------------------------------針對屬性進行驗證(在序列化器外部定義好一個函式,載入到序列化器的欄位上)
# 對某個欄位的選項進行驗證
def pub_date(value):
if value < date(2010, 1, 1):
raise serializers.ValidationError('日期必須實在2010-1-1日之後')
return value
class BookInfoSerializer(serializers.Serializer):
...
bpub_date = serializers.DateField(label='釋出日期', validators=[pub_date])
...
2.呼叫
serialiazer=模型類Serializer(data=字典)
serializer.is_valid()-----------進行驗證,如果成功則返回True,失敗則返回False
serialiser.error-----------------錯誤資訊,型別為字典
3.儲存
1.定義序列化器,增加create()、update()方法
2.呼叫:serializer.save()
PS:如果是建立:序列化器類(data=***)===>serializer.save()===>呼叫create()
如果是修改:序列化器類(模型類物件,data=***)===>serializer.save()=====>呼叫update()
如果是部分修改:序列化器類(模型類物件,data=***,partial=True)===>serializer.save()====>呼叫update()
跳過了必填的檢查