1. 程式人生 > >如何使用DRF的序列化器之序列化

如何使用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