Serializer序列器

定義Serializer數據庫

1. 定義方法

Django REST framework中的Serializer使用類來定義,須繼承自rest_framework.serializers.Serializer。 api

例如,咱們已有了一個數據庫模型類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)

咱們想爲這個模型類提供一個序列化器,能夠定義以下:post

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是獨立於數據庫以外的存在。測試

 

2. 字段與選項

 

經常使用字段類型ui

 

image

image

image

image

 

read_only:True表示不容許用戶本身上傳,只能用於api的輸出。若是某個字段設置了read_only=True,那麼就不須要進行數據驗證,只會在返回時,將這個字段序列化後返回url


write_only:與read_only對應;就是用戶post過來的數據,後臺服務器處理後不會再通過序列化後返回給客戶端;最多見的就是咱們在使用手機註冊的驗證碼和填寫的密碼。spa

 

3. 建立Serializer對象

Serializer的構造方法爲:3d

Serializer(instance=None, data=empty, **kwarg)

說明: rest

1)用於序列化時,將模型類對象傳入instance參數

2)用於反序列化時,將要被反序列化的數據傳入data參數

3)除了instance和data參數外,在構造Serializer對象時,還可經過context參數額外添加數據,如

serializer = AccountSerializer(account, context={'request': request})

經過context參數附加的數據,能夠經過Serializer對象的context屬性獲取。

 

Serializer使用

咱們定義一個測試視圖來使用序列化器,以下:

 

views

def test(request):
    return HttpResponse('ok')

urls

urlpatterns = [
    url(r'^test/$', views.test)
]

 

1. 基本使用

def test(request):
    book = BookInfo.objects.get(id=5)  # 先查詢出一個圖書對象
    serializer = BookInfoSerializer(book)  # 構建序列化
    print(serializer.data)  # 獲取序列化數據  {'image': None, 'btitle': '西遊記', 'id': 5, 'bread': 10, 'bcomment': 10, 'bpub_date': '1988-01-01'}

    return HttpResponse('ok')

若是要被序列化的是包含多條數據的查詢集QuerySet,能夠經過添加many=True參數補充說明

def test(request):
    book = BookInfo.objects.all()  # 先查詢出一個圖書對象
    serializer = BookInfoSerializer(book, many=True)  # 構建序列化
    print(serializer.data)  # 獲取序列化數據  {'image': None, 'btitle': '西遊記', 'id': 5, 'bread': 10, 'bcomment': 10, 'bpub_date': '1988-01-01'}

    return HttpResponse('ok')

2. 關聯對象嵌套序列化

若是須要序列化的數據中包含有其餘關聯對象,則對關聯對象數據的序列化須要指明。

例如,在定義英雄數據的序列化器時,外鍵hbook(即所屬的圖書)字段如何序列化?

咱們先定義HeroInfoSerialzier除外鍵字段外的其餘部分

對於關聯字段,能夠採用如下幾種方式:

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參數時,將被用做反序列化時參數校驗使用

使用效果:

def test(request):
    hero = HeroInfo.objects.get(id=10)  # 查詢一個英雄對象
    serializer = HeroInfoSerializer(hero) # 構建序列化
    print(serializer.data)  # 返回序列化內容 {'id': 10, 'hcomment': '獨孤九劍', 'hname': '令狐沖', 'hbook': 3, 'hgender': 1}
    return HttpResponse('ok')

 

報錯:說明id不存在

image

 

2. StringRelatedField

此字段將被序列化爲關聯對象的字符串表示方式(即__str__方法的返回值)

hbook = serializers.StringRelatedField(label='圖書')
def test(request):
    hero = HeroInfo.objects.get(id=11)  # 查詢一個英雄對象
    serializer = HeroInfoSerializer(hero) # 構建序列化
    print(serializer.data)  # 返回序列化內容 {'hgender': 0, 'hbook': '笑傲江湖', 'id': 11, 'hname': '任盈盈', 'hcomment': '彈琴'}
    return HttpResponse('ok')

 

3. 使用關聯對象的序列化器
hbook = BookInfoSerializer()

def test(request):
    hero = HeroInfo.objects.get(id=11)  # 查詢一個英雄對象
    serializer = HeroInfoSerializer(hero) # 構建序列化
    print(serializer.data)  # 返回序列化內容 {'hgender': 0, 'hbook': OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image', None)]), 'hcomment': '彈琴', 'id': 11, 'hname': '任盈盈'}
    return HttpResponse('ok')
4. HyperlinkedRelatedField

此字段將被序列化爲獲取關聯對象數據的接口連接

hbook = serializers.HyperlinkedRelatedField(label='圖書', read_only=True, view_name='books-detail')

必須指明view_name參數,以便DRF根據視圖名稱尋找路由,進而拼接成完整URL。

{'id': 6, 'hname': '喬峯', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': 'http://127.0.0.1:8000/books/2/'}

 

5. SlugRelatedField

此字段將被序列化爲關聯對象的指定字段數據

slug_field指明使用關聯對象的哪一個字段

hbook = serializers.SlugRelatedField(label='圖書', read_only=True, slug_field='bpub_date')
def test(request):
    hero = HeroInfo.objects.get(id=11)  # 查詢一個英雄對象
    serializer = HeroInfoSerializer(hero) # 構建序列化
    print(serializer.data)  # 返回序列化內容 {'id': 11, 'hgender': 0, 'hcomment': '彈琴', 'hname': '任盈盈', 'hbook': datetime.date(1995, 12, 24)}

    return HttpResponse('ok')

 

6. 重寫to_representation方法

序列化器的每一個字段實際都是由該字段類型的to_representation方法決定格式的,能夠經過重寫該方法來決定格式。

注意,to_representations方法不只侷限在控制關聯對象格式上,適用於各個序列化器字段類型。

自定義一個新的關聯字段:

class BookRelateField(serializers.RelatedField):
    """自定義用於處理圖書的字段"""
    def to_representation(self, value):
        return 'Book: %d %s' % (value.id, value.btitle)
hbook = BookRelateField(read_only=True)
def test(request):
    hero = HeroInfo.objects.get(id=11)  # 查詢一個英雄對象
    serializer = HeroInfoSerializer(hero) # 構建序列化
    print(serializer.data)  # 返回序列化內容 {'hbook': 'Book: 3 笑傲江湖', 'id': 11, 'hcomment': '彈琴', 'hname': '任盈盈', 'hgender': 0}
    return HttpResponse('ok')

 

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)  # 新增

使用效果:

def test(request):
    book = BookInfo.objects.get(id=3)  # 查詢一個英雄對象
    serializer = BookInfoSerializer(book) # 構建序列化
    print(serializer.data)  # 返回序列化內容 {'image': None, 'id': 3, 'bpub_date': '1995-12-24', 'bcomment': 80, 'bread': 20, 'heroinfo_set': [10, 11, 12, 13], 'btitle': '笑傲江湖'}

    return HttpResponse('ok')
相關文章
相關標籤/搜索