如何使用DRF的序列化器之序列化
DRF兩大利器為Serizlizer序列化器和檢視,而序列化器又分為序列化和反序列化,本篇文章首先來看下DRF序列化器的常用序列化方法。
首先來看使用Django開發REST介面時的表現,示例程式碼如下:
# views.py from datetime import datetime class BooksAPIVIew(View): """ 查詢所有圖書、增加圖書 """ def get(self, request): """ 查詢所有圖書 路由:GET /books/ """ queryset = BookInfo.objects.all() book_list = [] # 將BookInfo物件轉換為字典 for book in queryset: book_list.append({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }) # book_list為包含很多字典的列表 return JsonResponse(book_list, safe=False) def post(self, request): """ 新增圖書 路由:POST /books/ """ json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str) # 此處詳細的校驗引數省略 book = BookInfo.objects.create( btitle=book_dict.get('btitle'), bpub_date=datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date() ) return JsonResponse({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }, status=201)
當我們得到Queryset時或者得到一個BookInfo物件時,需要將BookInfo物件轉換為字典,將包含字典型別資料的列表轉換為json資料響應回去。其中將BookInfo物件轉換為字典的程式碼冗餘的厲害,此時serializer就可以大顯身手了。
使用序列化器首先需要在serializers.py中定義序列化器類:
欄位名稱和模型類中的欄位名相同,欄位的選項約束有很多,預設約束required為True!
詳細可以參看官方文件:https://www.django-rest-framework.org/
Github原始碼:https://github.com/encode/django-rest-framework/tree/master
# 需要繼承DRF的serilalizers中的Serializer from rest_framework import serializers from .models import BookInfo class BookSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) btitle = serializers.CharField( min_length=3, max_length=10, error_messages={ 'min_length': '書名要大於3個字元', 'max_length': '書名要小於10個字元' } ) bpub_date = serializers.DateField() bread = serializers.IntegerField() bcomment = serializers.IntegerField(label='評論量', required=False)
建立Serializer物件
定義好Serializer類後,就可以建立Serializer物件了。
Serializer的構造方法為:
Serializer(instance=None, data=empty, **kwarg)
說明:
1)用於序列化時,將模型類物件傳入instance引數
2)用於反序列化時,將要被反序列化的資料傳入data引數
3)除了instance和data引數外,在構造Serializer物件時,還可通過context引數額外新增資料,如
serializer = AccountSerializer(account, context={'request': request})
通過context引數附加的資料,可以通過Serializer物件的context屬性獲取
掌握了上述知識後我們就可以開始進行序列化操作了
class Book2View(View):
def get(self, request):
# 序列化列表
blist = BookInfo.objects.all()
# 1.建立序列化物件,如果被序列化的是包含多條資料的查詢集QuerySet
# 需要新增many=True引數補充說明
# 以列表為引數,列表中是模型類物件
serializer = serializers.BookSerializer(blist, many=True)
# 2.呼叫屬性data,通過data屬性可以獲取序列化後的資料
# 獲取轉換後的列表,列表中是有序字典物件
"""
[OrderedDict([('id', 2), ('btitle', '天龍八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40)]), OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80)])]
"""
book_dict_list = serializer.data
# 響應
return JsonResponse(book_dict_list, safe=False)
關聯物件巢狀序列化
如果需要序列化的資料中包含有其他關聯物件,則對關聯物件資料的序列化需要指明。注:書籍與英雄的關係為一對多
在定義序列化器類的程式碼中新增如下程式碼,注意在定義關聯屬性時,必須新增約束read_only = True
# 關係屬性輸出的3種方案
# 1.主鍵 此欄位將被序列化為關聯物件的主鍵。
# heros = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
# 2.字串
# heros = serializers.StringRelatedField(read_only=True, many=True)
# 3.自定義序列化器
heros = HeroSerializer(read_only=True, many=True)
如果關聯的物件資料不是隻有一個,而是包含多個數據,如想序列化圖書BookInfo資料,每個BookInfo物件關聯的英雄HeroInfo物件可能有多個,則在約束中新增many=True引數即可。
PrimaryKeyRelatedField: 此欄位將被序列化為關聯物件的主鍵
StringRelatedField:此欄位將被序列化為關聯物件的字串表示方式(即__str__方法的返回值)(定義模型類時新增__str__方法)
HeroSerializer:使用關聯物件的序列化器,需要自己定義關聯物件的序列化器
序列化器的序列化方法幫助我們封裝了將python型別(模型類物件、模型類物件的列表)轉換為字典的過程,加快開發效率。
# 將模型類物件轉換成字典的過程
serializer = serializers.HeroSerializer(hero)
hero_dict = serializer.data
# 將模型類物件的列表轉換為字典列表
serializer = serializers.BookSerializer(blist, many=True)
book_dict_list = serializer.data