乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      11 Serializer組件

       新進小設(shè)計 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, '商務(wù)印書館'),
              (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))
      
          # 自定義虛擬閱讀量,原基礎(chǔ)增加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. 在服務(wù)器響應(yīng)時,使用序列化器可以完成對數(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ù)是由[]嵌套,一定要設(shè)置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)可以設(shè)置校驗規(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響應(yīng)。

      # 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('圖書不是關(guān)于Django的')
              return value
      

      測試

      http://127.0.0.1:8000/bookinfo/
      {
          "btitle":"紅樓夢",
          "bpub_date":"2020-10-07"
      }
      
      {
          "btitle": [
              "圖書不是關(guān)于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-圖書不是關(guān)于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='圖書不是關(guān)于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, '商務(wù)印書館'),
              (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))
      
          # 自定義虛擬閱讀量,原基礎(chǔ)增加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-圖書不是關(guān)于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-圖書不是關(guān)于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)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約