11 Serializer組件

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

爲何要使用序列化組件?
視圖中查詢到的對象和queryset類型不能直接做爲數據返回給前臺,因此要使用序列化組件python

1. 定義Serializer

路由層 urls.pygit

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='發佈日期', null=True)
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="建立時間", help_text='建立時間')
    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

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

from rest_framework import serializers

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    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='發佈日期', required=False)
    created_time = serializers.DateTimeField(label='建立時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=False)
    bcomment = serializers.IntegerField(label='評論量', required=False)
    image = serializers.ImageField(label='圖片', required=False)
    """
    自定義序列化屬性
    格式:  屬性名隨意,值由固定的命名規範方法提供
    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不能直接做爲數據返回,由於內容雖然是字符串,可是類型是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不是隻能爲數據庫模型類定義,也能夠爲非數據庫模型類的數據定義。serializer是獨立於數據庫以外的存在。json

1.2 字段與選項

經常使用字段類型api

字段 字段構造方式
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: 最多位數 decimal_palces: 小數點位置
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=)

選項參數:安全

參數名稱 做用
max_length 最大長度
min_lenght 最小長度
allow_blank 是否容許爲空
trim_whitespace 是否截斷空白字符
max_value 最小值
min_value 最大值

通用參數:

參數名稱 說明
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 建立Serializer對象

定義好Serializer類後,就能夠建立Serializer對象了。服務器

Serializer的構造方法爲:restful

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

說明:

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

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

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

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

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

  1. 使用序列化器的時候必定要注意,序列化器聲明瞭之後,不會自動執行,須要咱們在視圖中進行調用才能夠

  2. 序列化器沒法直接接收數據,須要咱們在視圖中建立序列化器對象時把使用的數據傳遞過來。(data,instance傳參)

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

  3. 序列化器的字段聲明相似於咱們前面使用過的表單系統

  4. 開發restful api時,序列化器會幫咱們把模型數據轉換成字典。

  5. drf提供的視圖會幫咱們把字典轉換成json,或者把客戶端發過來的數據轉換成字典

2. 序列化器的使用

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

  1. 在客戶端請求時,使用序列化器能夠完成對數據的反序列化。
  2. 在服務器響應時,使用序列化器能夠完成對數據的序列化。
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) 構造序列化器
                book_ser = BookInfoSerializer(book_obj)
                # 3) 獲取序列化數據
                return Response({
                    'status': 200,
                    'msg': 0,
                    # 在序列化的時候沒有.data,那麼在傳給前端的時候必需要.data
                    'results': book_ser.data  # 經過data屬性能夠獲取序列化後的數據
                })
            except:
                return Response({
                    'status': 201,
                    'msg': '書籍信息不存在',
                })
        else:
            # 1) 查詢出圖書對象:對象列表(queryset)不能直接做爲數據返回給前臺
            book_obj_list = models.BookInfo.objects.all()
            # 2) 構造序列化器   PS:將對象交給序列化處理,產生序列化對象,若是序列化的數據是由[]嵌套,必定要設置many=True
            book_ser_data = BookInfoSerializer(book_obj_list, many=True)
            # 3) 獲取序列化數據
            return Response({
                'status': 200,
                'msg': 0,
                'results': book_ser_data.data  # 經過data屬性能夠獲取序列化後的數據
            })

3. 反序列化使用

3.1 驗證

  • 使用序列化器進行反序列化時,須要對數據進行驗證後,才能獲取驗證成功的數據或保存成模型類對象。
  • 在獲取反序列化的數據前,必須調用is_valid()方法進行驗證,驗證成功返回True,不然返回False。
    • 驗證失敗,能夠經過序列化器對象的errors屬性獲取錯誤信息,返回字典,包含了字段和字段的錯誤。若是是非字段錯誤,能夠經過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名。
    • 驗證成功,能夠經過序列化器對象的validated_data屬性獲取數據。
  • 在定義序列化器時,指明每一個字段的序列化類型和選項參數,自己就是一種驗證行爲。

3.2 使用事項

  1. 哪些字段必須反序列化
  2. 字段都有哪些安全校驗
  3. 哪些字段須要額外提供校驗 鉤子函數
  4. 哪些字段間存在聯合校驗
  5. 注:反序列化字段都是用來入庫的,不會出現自定義方法屬性,會出現能夠設置校驗規則的自定義屬性,不入數據庫的
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='發佈日期', 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)

3.3 驗證

3.3.1 is_valid

經過構造序列化器對象,並將要反序列化的數據傳遞給data構造參數,進而進行驗證

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': '數據有誤',
            })

        book_ser = BookInfoDeSerializer(data=request_data)
        
        # 序列化對象調用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參數開啓,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, 當前要校驗字段的值)

  • 校驗規則:校驗經過返回原值,校驗失敗,拋出異常

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...
    
	# 局部鉤子:validate_要校驗的字段名(self, 當前要校驗字段的值)
    # 校驗規則:校驗經過返回原值,校驗失敗,拋出異常
    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, 經過系統與局部鉤子校驗以後的全部數據)

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...   
    # 全局鉤子:validate(self, 經過系統與局部鉤子校驗以後的全部數據)
    def validate(self, attrs):  # attrs是字典格式
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')  # 由於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

3.3.3 validators

  • 在字段中添加validators選項參數,也能夠補充驗證行爲
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='發佈日期', 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)

測試:

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優先級

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

3.4 反序列化-保存數據

若是在驗證成功後,想要基於validated_data完成數據對象的建立,能夠經過實現create()和update()兩個方法來實現。

class BookInfoSerializer(serializers.Serializer):
    """圖書數據序列化器"""
    ...
    
    # 要完成新增,必須重寫create方法,validated_data是校驗的數據
    def create(self, validated_data):
        # 儘可能在全部校驗規則完畢以後,數據能夠直接入庫
        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

若是須要在返回數據對象的時候,也將數據保存到數據庫中,則能夠進行以下修改

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

    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

實現了上述兩個方法後,在反序列化數據的時候,就能夠經過save()方法返回一個數據對象實例了

book = serializer.save()

若是建立序列化器對象的時候,沒有傳遞instance實例,則調用save()方法的時候,create()被調用,相反,若是傳遞了instance實例,則調用save()方法的時候,update()被調用。

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='發佈日期', null=True)
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="建立時間", help_text='建立時間')
    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) 構造序列化器
                book_ser = BookInfoSerializer(instance=book_obj)
                # 3) 獲取序列化數據
                return Response({
                    'status': 200,
                    'msg': 0,
                    'results': book_ser.data  # 經過data屬性能夠獲取序列化後的數據
                })
            except:
                return Response({
                    'status': 201,
                    'msg': '書籍信息不存在',
                })
        else:
            # 1) 查詢出圖書對象
            book_obj_list = models.BookInfo.objects.all()
            # 2) 構造序列化器   PS:若是要被序列化的是包含多條數據的查詢集QuerySet,能夠經過添加many=True參數補充說明
            book_ser_data = BookInfoSerializer(instance=book_obj_list, many=True)
            # 3) 獲取序列化數據
            return Response({
                'status': 200,
                'msg': 0,
                'results': book_ser_data.data  # 經過data屬性能夠獲取序列化後的數據
            })

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

        book_ser = BookInfoDeSerializer(data=request_data)
        # 序列化對象調用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):
    """圖書數據序列化器"""
    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='發佈日期', required=False)
    created_time = serializers.DateTimeField(label='建立時間', required=False)
    bread = serializers.IntegerField(label='閱讀量', required=False)
    bcomment = serializers.IntegerField(label='評論量', required=False)
    image = serializers.ImageField(label='圖片', required=False)
    """
    自定義序列化屬性
    格式:  屬性名隨意,值由固定的命名規範方法提供
    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不能直接做爲數據返回,由於內容雖然是字符串,可是類型是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='發佈日期', 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)

    # 局部鉤子: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不須要存入數據庫,因此在全局鉤子校驗中刪除掉這個字段
        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是校驗的數據
    def create(self, validated_data):
        # 儘可能在全部校驗規則完畢以後,數據能夠直接入庫
        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()保存時,能夠額外傳遞數據,這些數據能夠在create()和update()中的validated_data參數獲取到

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

2)默認序列化器必須傳遞全部required的字段,不然會拋出驗證異常。可是咱們可使用partial參數來容許部分字段更新

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
相關文章
相關標籤/搜索