日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

11 Serializer組件

 新進小設計 2021-06-27

知識點:Serializer(偏底層)、ModelSerializer(重點)、ListModelSerializer(輔助群改)

為什么要使用序列化組件?
視圖中查詢到的對象和queryset類型不能直接作為數(shù)據(jù)返回給前臺,所以要使用序列化組件

1. 定義Serializer

路由層 urls.py

from django.urls import path, re_path
from .views import users

urlpatterns = [
    path('bookinfo/', users.BookInfo.as_view()),
    re_path('bookinfo/(?P<pk>.*)/$', users.BookInfo.as_view()),
]

模型層:models.py

1.1 定義方法

class BookInfo(models.Model):
    PUB_CHOICES = [
        (0, '商務印書館'),
        (1, '人民出版社'),
        (2, '人民文學出版社 '),
        (3, '作家出版社')
    ]
    pwd = models.CharField(max_length=32, verbose_name='密碼')
    publisher = models.IntegerField(choices=PUB_CHOICES, default=0, verbose_name='出版社')
    btitle = models.CharField(max_length=20, verbose_name='名稱')
    bpub_date = models.DateField(verbose_name='發(fā)布日期', null=True)
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="創(chuàng)建時間", help_text='創(chuàng)建時間')
    bread = models.IntegerField(default=0, verbose_name='閱讀量')
    bcomment = models.IntegerField(default=0, verbose_name='評論量')
    image = models.ImageField(upload_to='icon', verbose_name='圖片', default='icon/default.jpg')

    class Meta:
        db_table = 'BookInfo'
        verbose_name = '書籍信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s' % self.btitle

為這個模型類提供一個序列化器

from rest_framework import serializers

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    pwd = serializers.CharField(label='密碼', required=True)
    publisher = serializers.IntegerField(label='出版社')
    btitle = serializers.CharField(label='名稱', max_length=20)
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    created_time = serializers.DateTimeField(label='創(chuàng)建時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=False)
    bcomment = serializers.IntegerField(label='評論量', required=False)
    image = serializers.ImageField(label='圖片', required=False)
    """
    自定義序列化屬性
    格式:  屬性名隨意,值由固定的命名規(guī)范方法提供
    def get_屬性名(self, 參與序列化的model對象):
        返回值就是自定義序列化屬性的值
    """
    # 出版社顯示名稱,而不是0,1。。。
    publisher_name = serializers.SerializerMethodField()

    def get_publisher_name(self, obj):
        # choice類型的解釋型值 get_字段_display() 來訪問
        return obj.get_publisher_display()

    # 圖片顯示全路徑
    image_path = serializers.SerializerMethodField()

    def get_image_path(self, obj):
        # settings.MEDIA_URL: 自己配置的 /media/,給后面高級序列化與視圖類準備的
        # obj.icon不能直接作為數(shù)據(jù)返回,因為內(nèi)容雖然是字符串,但是類型是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

注意:serializer不是只能為數(shù)據(jù)庫模型類定義,也可以為非數(shù)據(jù)庫模型類的數(shù)據(jù)定義。serializer是獨立于數(shù)據(jù)庫之外的存在。

1.2 字段與選項

常用字段類型

字段 字段構(gòu)造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正則字段,驗證正則模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位數(shù) decimal_palces: 小數(shù)點位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices與Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

選項參數(shù):

參數(shù)名稱 作用
max_length 最大長度:在反序列化時進行輸入最大長度校驗
min_lenght 最小長度:在反序列化時進行輸入最小長度校驗
allow_blank 是否允許為空:在反序列化時允許傳空白字符串,默認不允許
trim_whitespace 是否截斷空白字符,默認True
max_value 最大值:在反序列化時進行輸入最大值校驗
min_value 最小值:在反序列化時進行輸入最小值校驗

通用參數(shù):

參數(shù)名稱 說明
read_only 表明該字段僅用于序列化輸出,默認False
write_only 表明該字段僅用于反序列化輸入,默認False
required 表明該字段在反序列化時必須輸入,默認True
default 反序列化時使用的默認值
allow_null 表明該字段是否允許傳入None,默認False
validators 該字段使用的驗證器
error_messages 包含錯誤編號與錯誤信息的字典
label 用于HTML展示API頁面時,顯示的字段名稱
help_text 用于HTML展示API頁面時,顯示的字段幫助提示信息

1.3 創(chuàng)建Serializer對象

定義好Serializer類后,就可以創(chuàng)建Serializer對象了。

Serializer的構(gòu)造方法為:

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

說明:

1)用于序列化時,將模型類對象傳入instance參數(shù)

2)用于反序列化時,將要被反序列化的數(shù)據(jù)傳入data參數(shù)

3)除了instance和data參數(shù)外,在構(gòu)造Serializer對象時,還可通過context參數(shù)額外添加數(shù)據(jù),如

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

通過context參數(shù)附加的數(shù)據(jù),可以通過Serializer對象的context屬性獲取。

  1. 使用序列化器的時候一定要注意,序列化器聲明了以后,不會自動執(zhí)行,需要我們在視圖中進行調(diào)用才可以

  2. 序列化器無法直接接收數(shù)據(jù),需要我們在視圖中創(chuàng)建序列化器對象時把使用的數(shù)據(jù)傳遞過來。(data,instance傳參)

    ?序列化是:數(shù)據(jù)對象從數(shù)據(jù)庫中查出,通過instance傳入序列化器中,必須通過data屬性才能將序列化后的數(shù)據(jù)傳給前端,不能直接傳序列化對象
    ?反序列化是:數(shù)據(jù)是通過request.data從前端獲取到數(shù)據(jù),通過data傳入序列化器中進行校驗,保存到數(shù)據(jù)庫中

  3. 序列化器的字段聲明類似于我們前面使用過的表單系統(tǒng)

  4. 開發(fā)restful api時,序列化器會幫我們把模型數(shù)據(jù)轉(zhuǎn)換成字典。

  5. drf提供的視圖會幫我們把字典轉(zhuǎn)換成json,或者把客戶端發(fā)過來的數(shù)據(jù)轉(zhuǎn)換成字典

2. 序列化器的使用

序列化器的使用分兩個階段:

  1. 在客戶端請求時,使用序列化器可以完成對數(shù)據(jù)的反序列化。
  2. 在服務器響應時,使用序列化器可以完成對數(shù)據(jù)的序列化。
from .. import models
from ..serializers import BookInfoSerializer


class BookInfo(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            try:
                # 1) 查詢出圖書對象
                book_obj = models.BookInfo.objects.get(pk=pk)
                # 2) 構(gòu)造序列化器
                book_ser = BookInfoSerializer(book_obj)
                # 3) 獲取序列化數(shù)據(jù)
                return Response({
                    'status': 200,
                    'msg': 0,
                    # 在序列化的時候沒有.data,那么在傳給前端的時候必須要.data
                    'results': book_ser.data  # 通過data屬性可以獲取序列化后的數(shù)據(jù)
                })
            except:
                return Response({
                    'status': 201,
                    'msg': '書籍信息不存在',
                })
        else:
            # 1) 查詢出圖書對象:對象列表(queryset)不能直接作為數(shù)據(jù)返回給前臺
            book_obj_list = models.BookInfo.objects.all()
            # 2) 構(gòu)造序列化器   PS:將對象交給序列化處理,產(chǎn)生序列化對象,如果序列化的數(shù)據(jù)是由[]嵌套,一定要設置many=True
            book_ser_data = BookInfoSerializer(book_obj_list, many=True)
            # 3) 獲取序列化數(shù)據(jù)
            return Response({
                'status': 200,
                'msg': 0,
                'results': book_ser_data.data  # 通過data屬性可以獲取序列化后的數(shù)據(jù)
            })

3. 反序列化使用

3.1 驗證

  • 使用序列化器進行反序列化時,需要對數(shù)據(jù)進行驗證后,才能獲取驗證成功的數(shù)據(jù)或保存成模型類對象。
  • 在獲取反序列化的數(shù)據(jù)前,必須調(diào)用is_valid()方法進行驗證,驗證成功返回True,否則返回False。
    • 驗證失敗,可以通過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。如果是非字段錯誤,可以通過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名。
    • 驗證成功,可以通過序列化器對象的validated_data屬性獲取數(shù)據(jù)。
  • 在定義序列化器時,指明每個字段的序列化類型和選項參數(shù),本身就是一種驗證行為。

3.2 使用事項

  1. 哪些字段必須反序列化
  2. 字段都有哪些安全校驗
  3. 哪些字段需要額外提供校驗 鉤子函數(shù)
  4. 哪些字段間存在聯(lián)合校驗
  5. 注:反序列化字段都是用來入庫的,不會出現(xiàn)自定義方法屬性,會出現(xiàn)可以設置校驗規(guī)則的自定義屬性,不入數(shù)據(jù)庫的
class BookInfoDeSerializer(serializers.Serializer):
    """圖書序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    pwd = serializers.CharField(label='密碼', required=True)
    publisher = serializers.IntegerField(label='出版社', required=False)
    btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    created_time = serializers.DateTimeField(label='創(chuàng)建時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=True)
    bcomment = serializers.IntegerField(label='評論量', required=True)
    image = serializers.ImageField(label='圖片', required=False)

    # 自定義有校驗規(guī)則的反序列化字段,例如確認密碼字段re_pwd
    re_pwd = serializers.CharField(required=True)

3.3 驗證

3.3.1 is_valid

通過構(gòu)造序列化器對象,并將要反序列化的數(shù)據(jù)傳遞給data構(gòu)造參數(shù),進而進行驗證

class BookInfo(APIView):  # 單增
    def post(self, request, *args, **kwargs):
        request_data = request.data
        if not isinstance(request_data, dict) or request_data == {}:
            return Response({
                'status': 1,
                'msg': '數(shù)據(jù)有誤',
            })

        book_ser = BookInfoDeSerializer(data=request_data)
        
        # 序列化對象調(diào)用is_valid()完成校驗,校驗失敗的失敗信息都會被存儲在 序列化對象.errors
        # 檢驗是否合格 raise_exception=True必填的
        book_ser.is_valid(raise_exception=True)
        # book_result是對象<class 'app01.models.Book'>,群增就是列表套一個個對象
        book_obj = book_ser.save()
        return Response({
            'status': 200,
            'msg': 'ok',
            'results': BookInfoSerializer(instance=book_obj).data
        })
上面兩句和下面是一樣的
        # if book_ser.is_valid():
        #     # 校驗通過,完成新增
        #     book_obj = book_ser.save()
        #     return Response({
        #         'status': 0,
        #         'msg': 'ok',
        #         'results': BookInfoSerializer(instance=book_obj).data
        #     })
        # else:
        #     # 校驗失敗
        #     return Response({
        #         'status': 1,
        #         'msg': book_ser.errors,
        #     })

is_valid()方法還可以在驗證失敗時拋出異常serializers.ValidationError

可以通過傳遞raise_exception=True參數(shù)開啟,REST framework接收到此異常,會向前端返回HTTP 400 Bad Request響應。

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

如果還不夠,需要在補充定義驗證行為,可以使用一下三種方法

3.3.2 validate_<field_name>-局部鉤子

  • <field_name>字段進行驗證

  • 局部鉤子:validate_要校驗的字段名(self, 當前要校驗字段的值)

  • 校驗規(guī)則:校驗通過返回原值,校驗失敗,拋出異常

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...
    
# 局部鉤子:validate_要校驗的字段名(self, 當前要校驗字段的值)
    # 校驗規(guī)則:校驗通過返回原值,校驗失敗,拋出異常
    def validate_btitle(self, value):
        if 'django' not in value.lower():
            raise exceptions.ValidationError('圖書不是關于Django的')
        return value

測試

http://127.0.0.1:8000/bookinfo/
{
    "btitle":"紅樓夢",
    "bpub_date":"2020-10-07"
}

{
    "btitle": [
        "圖書不是關于Django的"
    ]
}

3.3.2 validate-全局鉤子

  • 在序列化器中需要同時對多個字段進行比較驗證時,可以定義validate方法來驗證

  • 全局鉤子:validate(self, 通過系統(tǒng)與局部鉤子校驗之后的所有數(shù)據(jù))

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...   
    # 全局鉤子:validate(self, 通過系統(tǒng)與局部鉤子校驗之后的所有數(shù)據(jù))
    def validate(self, attrs):  # attrs是字典格式
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')  # 因為re_pwd不需要存入數(shù)據(jù)庫,所以在全局鉤子校驗中刪除掉這個字段
        bread = attrs['bread']
        bcomment = attrs['bcomment']
        if pwd != re_pwd:
            raise exceptions.ValidationError({'pwd&re_pwd': '兩次密碼不一致'})
        if bread < bcomment:
            raise serializers.ValidationError('閱讀量小于評論量')
        return attrs

3.3.3 validators

  • 在字段中添加validators選項參數(shù),也可以補充驗證行為
def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("validators-圖書不是關于Django的")

class BookInfoDeSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    pwd = serializers.CharField(label='密碼', required=True)
    publisher = serializers.IntegerField(label='出版社', required=False)
    btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    created_time = serializers.DateTimeField(label='創(chuàng)建時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=True)
    bcomment = serializers.IntegerField(label='評論量', required=True)
    image = serializers.ImageField(label='圖片', required=False)

測試:

Copyfrom booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid()  # False   
serializer.errors
#  {'btitle': [ErrorDetail(string='圖書不是關于Django的', code='invalid')]}

3.3.4 validators、validate_<field_name>、validate優(yōu)先級

validators--->validate_<field_name>(局部)----->validate(全局)

3.4 反序列化-保存數(shù)據(jù)

如果在驗證成功后,想要基于validated_data完成數(shù)據(jù)對象的創(chuàng)建,可以通過實現(xiàn)create()和update()兩個方法來實現(xiàn)。

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...
    
    # 要完成新增,必須重寫create方法,validated_data是校驗的數(shù)據(jù)
    def create(self, validated_data):
        # 盡量在所有校驗規(guī)則完畢之后,數(shù)據(jù)可以直接入庫
        return models.User.objects.create(**validated_data)
    
    def update(self, instance, validated_data):
        """更新,instance為要更新的對象實例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.pwd = validated_data.get('pwd', instance.pwd)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        return instance

如果需要在返回數(shù)據(jù)對象的時候,也將數(shù)據(jù)保存到數(shù)據(jù)庫中,則可以進行如下修改

class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    ...

    def create(self, validated_data):
        """新建"""
        return BookInfo.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """更新,instance為要更新的對象實例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        instance.save()
        return instance

實現(xiàn)了上述兩個方法后,在反序列化數(shù)據(jù)的時候,就可以通過save()方法返回一個數(shù)據(jù)對象實例了

book = serializer.save()

如果創(chuàng)建序列化器對象的時候,沒有傳遞instance實例,則調(diào)用save()方法的時候,create()被調(diào)用,相反,如果傳遞了instance實例,則調(diào)用save()方法的時候,update()被調(diào)用。

models.py

from django.db import models

class BookInfo(models.Model):
    PUB_CHOICES = [
        (0, '商務印書館'),
        (1, '人民出版社'),
        (2, '人民文學出版社 '),
        (3, '作家出版社')
    ]
    pwd = models.CharField(max_length=32, verbose_name='密碼')
    publisher = models.IntegerField(choices=PUB_CHOICES, default=0, verbose_name='出版社')
    btitle = models.CharField(max_length=20, verbose_name='名稱')
    bpub_date = models.DateField(verbose_name='發(fā)布日期', null=True)
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="創(chuàng)建時間", help_text='創(chuàng)建時間')
    bread = models.IntegerField(default=0, verbose_name='閱讀量')
    bcomment = models.IntegerField(default=0, verbose_name='評論量')
    image = models.ImageField(upload_to='icon', verbose_name='圖片', default='icon/default.jpg')

    class Meta:
        db_table = 'BookInfo'
        verbose_name = '書籍信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s' % self.btitle

路由:urls


from django.urls import path, re_path
from .views import test, users, books, v2books

urlpatterns = [
    path('bookinfo/', users.BookInfo.as_view()),
    re_path('bookinfo/(?P<pk>.*)/$', users.BookInfo.as_view()),
]

views視圖

rom rest_framework.views import APIView
from rest_framework.response import Response

from .. import models
from ..serializers import UserSerializer, UserDeserializer, BookInfoSerializer, BookInfoDeSerializer


class BookInfo(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            try:
                # 1) 查詢出圖書對象
                book_obj = models.BookInfo.objects.get(pk=pk)
                # 2) 構(gòu)造序列化器
                book_ser = BookInfoSerializer(instance=book_obj)
                # 3) 獲取序列化數(shù)據(jù)
                return Response({
                    'status': 200,
                    'msg': 0,
                    'results': book_ser.data  # 通過data屬性可以獲取序列化后的數(shù)據(jù)
                })
            except:
                return Response({
                    'status': 201,
                    'msg': '書籍信息不存在',
                })
        else:
            # 1) 查詢出圖書對象
            book_obj_list = models.BookInfo.objects.all()
            # 2) 構(gòu)造序列化器   PS:如果要被序列化的是包含多條數(shù)據(jù)的查詢集QuerySet,可以通過添加many=True參數(shù)補充說明
            book_ser_data = BookInfoSerializer(instance=book_obj_list, many=True)
            # 3) 獲取序列化數(shù)據(jù)
            return Response({
                'status': 200,
                'msg': 0,
                'results': book_ser_data.data  # 通過data屬性可以獲取序列化后的數(shù)據(jù)
            })

    def post(self, request, *args, **kwargs):
        request_data = request.data
        if not isinstance(request_data, dict) or request_data == {}:
            return Response({
                'status': 1,
                'msg': '數(shù)據(jù)有誤',
            })

        book_ser = BookInfoDeSerializer(data=request_data)
        # 序列化對象調(diào)用is_valid()完成校驗,校驗失敗的失敗信息都會被存儲在 序列化對象.errors
        # 檢驗是否合格 raise_exception=True必填的
        book_ser.is_valid(raise_exception=True)
        # book_result是對象<class 'app01.models.Book'>,群增就是列表套一個個對象
        book_obj = book_ser.save()
        return Response({
            'status': 200,
            'msg': 'ok',
            'results': BookInfoSerializer(instance=book_obj).data
        })

        # if book_ser.is_valid():
        #     # 校驗通過,完成新增
        #     book_obj = book_ser.save()
        #     return Response({
        #         'status': 0,
        #         'msg': 'ok',
        #         'results': BookInfoSerializer(instance=book_obj).data
        #     })
        # else:
        #     # 校驗失敗
        #     return Response({
        #         'status': 1,
        #         'msg': book_ser.errors,
        #     })

serializers.py

from rest_framework import serializers
from django.conf import settings
from rest_framework.exceptions import ValidationError
from . import models

# 序列化
class BookInfoSerializer(serializers.Serializer):
    """圖書數(shù)據(jù)序列化器"""
    id = serializers.IntegerField(label='ID', read_only=True)
    pwd = serializers.CharField(label='密碼', required=True)
    publisher = serializers.IntegerField(label='出版社', required=False)
    btitle = serializers.CharField(label='名稱', max_length=20)
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    created_time = serializers.DateTimeField(label='創(chuàng)建時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=False)
    bcomment = serializers.IntegerField(label='評論量', required=False)
    image = serializers.ImageField(label='圖片', required=False)
    """
    自定義序列化屬性
    格式:  屬性名隨意,值由固定的命名規(guī)范方法提供
    def get_屬性名(self, 參與序列化的model對象):
        返回值就是自定義序列化屬性的值
    """
    # 出版社顯示名稱,而不是0,1。。。
    publisher_name = serializers.SerializerMethodField()

    def get_publisher_name(self, obj):
        # choice類型的解釋型值 get_字段_display() 來訪問
        return obj.get_publisher_display()

    # 圖片顯示全路徑
    image_path = serializers.SerializerMethodField()

    def get_image_path(self, obj):
        # settings.MEDIA_URL: 自己配置的 /media/,給后面高級序列化與視圖類準備的
        # obj.icon不能直接作為數(shù)據(jù)返回,因為內(nèi)容雖然是字符串,但是類型是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


def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("validators-圖書不是關于Django的")

# 反序列化
class BookInfoDeSerializer(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    pwd = serializers.CharField(label='密碼', required=True)
    publisher = serializers.IntegerField(label='出版社', required=False)
    btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
    bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
    created_time = serializers.DateTimeField(label='創(chuàng)建時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=True)
    bcomment = serializers.IntegerField(label='評論量', required=True)
    image = serializers.ImageField(label='圖片', required=False)

    # 自定義有校驗規(guī)則的反序列化字段,例如確認密碼字段re_pwd
    re_pwd = serializers.CharField(required=True)

    # 局部鉤子:validate_要校驗的字段名(self, 當前要校驗字段的值)
    # 校驗規(guī)則:校驗通過返回原值,校驗失敗,拋出異常
    def validate_btitle(self, value):
        if 'django' not in value.lower():
            raise exceptions.ValidationError('validate_btitle-圖書不是關于Django的')
        return value

    # 全局鉤子:validate(self, 通過系統(tǒng)與局部鉤子校驗之后的所有數(shù)據(jù))
    def validate(self, attrs):  # attrs是字典格式
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')  # 因為re_pwd不需要存入數(shù)據(jù)庫,所以在全局鉤子校驗中刪除掉這個字段
        bread = attrs['bread']
        bcomment = attrs['bcomment']
        if pwd != re_pwd:
            raise exceptions.ValidationError({'pwd&re_pwd': '兩次密碼不一致'})
        if bread < bcomment:
            raise serializers.ValidationError('閱讀量小于評論量')
        return attrs

    # 要完成新增,必須重寫create方法,validated_data是校驗的數(shù)據(jù)
    def create(self, validated_data):
        # 盡量在所有校驗規(guī)則完畢之后,數(shù)據(jù)可以直接入庫
        return models.User.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """更新,instance為要更新的對象實例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.pwd = validated_data.get('pwd', instance.pwd)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        return instance

3.5 附加說明

1) 在對序列化器進行save()保存時,可以額外傳遞數(shù)據(jù),這些數(shù)據(jù)可以在create()和update()中的validated_data參數(shù)獲取到

# request.user 是django中記錄當前登錄用戶的模型對象
serializer.save(owner=request.user)

2)默認序列化器必須傳遞所有required的字段,否則會拋出驗證異常。但是我們可以使用partial參數(shù)來允許部分字段更新

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約