模型類序列化器ModelSerializer
如果我們想要使用序列化器對應的是Django的模型類,DRF為我們提供了ModelSerializer模型類序列化器來幫助我們快速創建一個Serializer類,
ModelSerializer與常規的Serializer相同,但提供了:
- 基于模型類自動生成一系列欄位
- 基于模型類自動為Serializer生成validators,比如unique_together
- 包含默認的create()和update()的實作
1. 定義
比如我們創建一個BookInfoSerializer:
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = '__all__'
- model 指明參照哪個模型類
- fields 指明為模型類的哪些欄位生成
我們可以在python manage.py shell中查看自動生成的BookInfoSerializer的具體實作
>>> from booktest.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
id = IntegerField(label='ID', read_only=True)
btitle = CharField(label='名稱', max_length=20)
bpub_date = DateField(allow_null=True, label='發布日期', required=False)
bread = IntegerField(label='閱讀量', max_value=https://www.cnblogs.com/LYPZX/p/2147483647, min_value=-2147483648, required=False)
bcomment = IntegerField(label='評論量', max_value=https://www.cnblogs.com/LYPZX/p/2147483647, min_value=-2147483648, required=False)
image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)
2. 指定欄位
- 使用fields來明確欄位,
__all__表名包含所有欄位,也可以寫明具體哪些欄位,如
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date')
- 使用exclude可以明確排除掉哪些欄位
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
exclude = ('image',)
- 顯示指明欄位,如:
class HeroInfoSerializer(serializers.ModelSerializer):
hbook = BookInfoSerializer()
class Meta:
model = HeroInfo
fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
- 指明只讀欄位
可以通過read_only_fields指明只讀欄位,即僅用于序列化輸出的欄位
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
read_only_fields = ('id', 'bread', 'bcomment')
3. 添加額外引數
我們可以使用extra_kwargs引數為ModelSerializer添加或修改原有的選項引數
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
extra_kwargs = {
'bread': {'min_value': 0, 'required': True},
'bcomment': {'min_value': 0, 'required': True},
}
基于 Serializer組件的model、urls、views使用serializers.ModelSerializer重寫
4. 序列化
class BookInfoModelSerializer(serializers.ModelSerializer):
# 1.還可以自定義設定序列化欄位,但是必須在fields中宣告,在fields中寫publish_address
# 出版社顯示名稱,而不是0,1,,,
publish_address = serializers.CharField(source='get_publisher_display', required=False) # 找到對應中文
# 圖片顯示全路徑
image_path = serializers.SerializerMethodField()
def get_image_path(self, obj):
# settings.MEDIA_URL: 自己配置的 /media/,給后面高級序列化與視圖類準備的
# obj.icon不能直接作為資料回傳,因為內容雖然是字串,但是型別是ImageFieldFile型別
return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.image))
# 自定義虛擬閱讀量,原基礎增加10
fictitious_bread = serializers.SerializerMethodField()
def get_fictitious_bread(self, obj):
return obj.bread + 10
class Meta:
# 序列化關聯的model類
model = models.BookInfo
# 參與序列化的欄位
fields = (
'id', 'pwd', 'publisher', 'publish_address', 'btitle', 'bpub_date', 'created_time', 'bread',
'fictitious_bread', 'bcomment', 'image', 'image_path')
# 指明只讀欄位,即僅用于序列化輸出的欄位
read_only_fields = ('publisher_name', 'fictitious_bread', 'image_path')
5. 反序列化
class BookInfoModelDeSerializer(serializers.ModelSerializer):
pwd = serializers.CharField(label='密碼', required=True)
publisher = serializers.IntegerField(label='出版社', required=False)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發布日期', required=False)
created_time = serializers.DateTimeField(label='創建時間', required=False)
bread = serializers.IntegerField(label='閱讀量', required=True)
bcomment = serializers.IntegerField(label='評論量', required=True)
image = serializers.ImageField(label='圖片', required=False)
# 自定義有校驗規則的反序列化欄位,例如確認密碼欄位re_pwd
re_pwd = serializers.CharField(required=True)
class Meta:
model = models.BookInfo
# 沒有默認值的欄位必須序列化,為其傳值
fields = ('pwd', 're_pwd', 'publisher', 'btitle', 'bpub_date', 'created_time', 'bread', 'bcomment', 'image')
# 區域鉤子:validate_要校驗的欄位名(self, 當前要校驗欄位的值)
# 校驗規則:校驗通過回傳原值,校驗失敗,拋出例外
def validate_btitle(self, value):
if 'django' not in value.lower():
raise exceptions.ValidationError('validate_btitle-圖書不是關于Django的')
return value
# 全域鉤子:validate(self, 通過系統與區域鉤子校驗之后的所有資料)
def validate(self, attrs): # attrs是字典格式
pwd = attrs.get('pwd')
re_pwd = attrs.pop('re_pwd') # 因為re_pwd不需要存入資料庫,所以在全域鉤子校驗中洗掉掉這個欄位
print(re_pwd)
bread = attrs['bread']
bcomment = attrs['bcomment']
if pwd != re_pwd:
raise exceptions.ValidationError({'pwd&re_pwd': '兩次密碼不一致'})
if bread < bcomment:
raise serializers.ValidationError('閱讀量小于評論量')
return attrs
# 注意:ModelSerializer類已經幫我們實作了 create 與 update 方法,不需要寫create就能創建
6 序列化與反序列化整合
序列化層:api/serializers.py
class BookModelSerializer(serializers.ModelSerializer):
pwd = serializers.CharField(label='密碼', required=True)
publisher = serializers.IntegerField(label='出版社', required=False)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發布日期', required=False)
created_time = serializers.DateTimeField(label='創建時間', required=False)
bread = serializers.IntegerField(label='閱讀量', required=True)
bcomment = serializers.IntegerField(label='評論量', required=True)
image = serializers.ImageField(label='圖片', required=False)
# 序列化自定義欄位
# 出版社顯示名稱,而不是0,1,,,
publisher_name = serializers.CharField(source='get_publisher_display', required=False) # 找到對應中文
# 圖片顯示全路徑
image_path = serializers.SerializerMethodField()
# 自定義虛擬閱讀量,原基礎增加10
fictitious_bread = serializers.SerializerMethodField()
# 反序列化自定義欄位
re_pwd = serializers.CharField(required=True, write_only=True)
class Meta:
model = models.BookInfo
fields = "__all__"
# 只讀欄位
read_only_fields = (
'id', 'pwd', 'publisher', 'publisher_name', 'btitle', 'bpub_date', 'created_time', 'bread',
'fictitious_bread', 'bcomment', 'image', 'image_path')
extra_kwargs = {
'pwd': {
'write_only': True
},
're_pwd': {
'write_only': True
},
'bpub_date': {
'write_only': True
},
'publisher': {
'write_only': True,
},
'img': {
'read_only': True,
},
'created_time': {
'read_only': True,
},
'publish_name': {
'read_only': True,
}
}
def get_image_path(self, obj):
# settings.MEDIA_URL: 自己配置的 /media/,給后面高級序列化與視圖類準備的
# obj.icon不能直接作為資料回傳,因為內容雖然是字串,但是型別是ImageFieldFile型別
return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.image))
def get_fictitious_bread(self, obj):
return obj.bread + 10
# 區域鉤子:validate_要校驗的欄位名(self, 當前要校驗欄位的值)
# 校驗規則:校驗通過回傳原值,校驗失敗,拋出例外
def validate_btitle(self, value):
if 'django' not in value.lower():
raise exceptions.ValidationError('validate_btitle-圖書不是關于Django的')
return value
# 全域鉤子:validate(self, 通過系統與區域鉤子校驗之后的所有資料)
def validate(self, attrs): # attrs是字典格式
pwd = attrs.get('pwd')
re_pwd = attrs.pop('re_pwd') # 因為re_pwd不需要存入資料庫,所以在全域鉤子校驗中洗掉掉這個欄位
print(re_pwd)
bread = attrs['bread']
bcomment = attrs['bcomment']
if pwd != re_pwd:
raise exceptions.ValidationError({'pwd&re_pwd': '兩次密碼不一致'})
if bread < bcomment:
raise serializers.ValidationError('閱讀量小于評論量')
return attrs
# 注意:ModelSerializer類已經幫我們實作了 create 與 update 方法,不需要寫create就能創建
序列化層注意點:
1) fields中設定所有序列化與反序列化欄位
2) extra_kwargs劃分只序列化或只反序列化欄位(一般我們把需要存入到資料庫中的使用write_only(反序列化),只需要展示的就read_only(序列化),看需求設計)
write_only:只反序列化
read_only:只序列化
自定義欄位默認只序列化(read_only)
如果欄位沒設定write_only或者read_only,那么該欄位可以序列化和反序列化
3) 設定反序列化所需的 系統、區域鉤子、全域鉤子 等校驗規則
7 ModelSerializer總結
class BookSerializer(serializers.ModelSerializer):
model欄位或自定義欄位
class Meta:
model = models.BookInfo # 與BookInfo表對應
# 使用fields來明確欄位,__all__表名包含所有欄位,也可以寫明具體哪些欄位
fields=('參與序列化和反序列的欄位1','參與序列化和反序列的欄位2')
fields = "__all__"
# 使用exclude可以明確排除掉哪些欄位
exclude = ('image',)
# 指明只讀欄位 通過read_only_fields指明只讀欄位,即僅用于序列化輸出的欄位
read_only_fields = ('id', 'bread', 'bcomment')
# 為ModelSerializer添加或修改原有的選項引數
extra_kwargs = {
}
# 區域鉤子:validate_要校驗的欄位名(self, 當前要校驗欄位的值)
# 校驗規則:校驗通過回傳原值,校驗失敗,拋出例外
def validate_btitle(self, value):
....
return value
# 全域鉤子:validate(self, 通過系統與區域鉤子校驗之后的所有資料)
def validate(self, attrs): # attrs是字典格式
...
return attrs
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/228406.html
標籤:Python
