<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Django REST framework

      1.引入Django REST framework

      1.1使用Django開發(fā)REST 接口

      我們以在Django框架中使用的圖書英雄案例來寫一套支持圖書數(shù)據(jù)增刪改查的REST API接口,來理解REST API的開發(fā)。

      在此案例中,前后端均發(fā)送JSON格式數(shù)據(jù)。

      # views.py
      
      from datetime import datetime
      
      class BooksAPIVIew(View):
          """
          查詢所有圖書、增加圖書
          """
          def get(self, request):
              """
              查詢所有圖書
              路由:GET /books/
              """
              queryset = BookInfo.objects.all()
              book_list = []
              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 ''
                  })
              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) class BookAPIView(View): def get(self, request, pk): """ 獲取單個(gè)圖書信息 路由: GET /books/<pk>/ """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) 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 '' }) def put(self, request, pk): """ 修改圖書信息 路由: PUT /books/<pk> """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str) book.btitle = book_dict.get('btitle') book.bpub_date = datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date() book.save() 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 '' }) def delete(self, request, pk): """ 刪除圖書 路由: DELETE /books/<pk>/ """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) book.delete() return HttpResponse(status=204)
      # urls.py
      
      urlpatterns = [
          url(r'^books/$', views.BooksAPIVIew.as_view()),
          url(r'^books/(?P<pk>\d+)/$', views.BookAPIView.as_view())
      ]

      測試

      使用Postman測試上述接口

      1) 獲取所有圖書數(shù)據(jù)

      GET 方式訪問 http://127.0.0.1:8000/books/, 返回狀態(tài)碼200,數(shù)據(jù)如下

      [
          {
              "id": 1,
              "btitle": "射雕英雄傳",
              "bpub_date": "1980-05-01",
              "bread": 12,
              "bcomment": 34,
              "image": ""
          },
          {
              "id": 2,
              "btitle": "天龍八部",
              "bpub_date": "1986-07-24",
              "bread": 36,
              "bcomment": 40,
              "image": ""
          },
          {
              "id": 3,
              "btitle": "笑傲江湖",
              "bpub_date": "1995-12-24",
              "bread": 20,
              "bcomment": 80,
              "image": ""
          },
          {
              "id": 4,
              "btitle": "雪山飛狐",
              "bpub_date": "1987-11-11",
              "bread": 58,
              "bcomment": 24,
              "image": ""
          },
          {
              "id": 5,
              "btitle": "西游記",
              "bpub_date": "1988-01-01",
              "bread": 10,
              "bcomment": 10,
              "image": "booktest/xiyouji.png"
          },
          {
              "id": 6,
              "btitle": "水滸傳",
              "bpub_date": "1992-01-01",
              "bread": 10,
              "bcomment": 11,
              "image": ""
          },
          {
              "id": 7,
              "btitle": "紅樓夢",
              "bpub_date": "1990-01-01",
              "bread": 0,
              "bcomment": 0,
              "image": ""
          }
      ]


      2)獲取單一圖書數(shù)據(jù)

      GET 訪問 http://127.0.0.1:8000/books/5/ ,返回狀態(tài)碼200, 數(shù)據(jù)如下

      {
          "id": 5,
          "btitle": "西游記",
          "bpub_date": "1988-01-01",
          "bread": 10,
          "bcomment": 10,
          "image": "booktest/xiyouji.png"
      }

      GET 訪問http://127.0.0.1:8000/books/100/,返回狀態(tài)碼404


      3)新增圖書數(shù)據(jù)

      POST 訪問http://127.0.0.1:8000/books/,發(fā)送JSON數(shù)據(jù):

      {
          "btitle": "三國演義",
          "bpub_date": "1990-02-03"
      }

      返回狀態(tài)碼201,數(shù)據(jù)如下

      {
          "id": 8,
          "btitle": "三國演義",
          "bpub_date": "1990-02-03",
          "bread": 0,
          "bcomment": 0,
          "image": ""
      }


      4)修改圖書數(shù)據(jù)

      PUT 訪問http://127.0.0.1:8000/books/8/,發(fā)送JSON數(shù)據(jù):

      {
          "btitle": "三國演義(第二版)",
          "bpub_date": "1990-02-03"
      }

      返回狀態(tài)碼200,數(shù)據(jù)如下

      {
          "id": 8,
          "btitle": "三國演義(第二版)",
          "bpub_date": "1990-02-03",
          "bread": 0,
          "bcomment": 0,
          "image": ""
      }


      5)刪除圖書數(shù)據(jù)

      DELETE 訪問http://127.0.0.1:8000/books/8/,返回204狀態(tài)碼

       

      1.2 明確REST接口開發(fā)的核心任務(wù)

      分析一下上節(jié)的案例,可以發(fā)現(xiàn),在開發(fā)REST API接口時(shí),視圖中做的最主要有三件事:

      • 將請求的數(shù)據(jù)(如JSON格式)轉(zhuǎn)換為模型類對象
      • 操作數(shù)據(jù)庫
      • 將模型類對象轉(zhuǎn)換為響應(yīng)的數(shù)據(jù)(如JSON格式)


      序列化Serialization

      序列化理解為:將程序中的一個(gè)數(shù)據(jù)結(jié)構(gòu)類型轉(zhuǎn)換為其他格式(字典、JSON、XML等),例如將Django中的模型類對象裝換為JSON字符串,這個(gè)轉(zhuǎn)換過程我們稱為序列化。

      如:

      queryset = BookInfo.objects.all()
      book_list = []
      # 序列化
      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 ''
          })
      return JsonResponse(book_list, safe=False)

       

      反之,將其他格式(字典、JSON、XML等)轉(zhuǎn)換為程序中的數(shù)據(jù),例如將JSON字符串轉(zhuǎn)換為Django中的模型類對象,這個(gè)過程我們稱為反序列化。

      如:

      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()
      )

      我們可以看到,在開發(fā)REST API時(shí),視圖中要頻繁的進(jìn)行序列化與反序列化的編寫。

      總結(jié)

      在開發(fā)REST API接口時(shí),我們在視圖中需要做的最核心的事是:

      • 將數(shù)據(jù)庫數(shù)據(jù)序列化為前端所需要的格式,并返回;

      • 將前端發(fā)送的數(shù)據(jù)反序列化為模型類對象,并保存到數(shù)據(jù)庫中。

       

      1.3Django REST framework 簡介

      1. 在序列化與反序列化時(shí),雖然操作的數(shù)據(jù)不盡相同,但是執(zhí)行的過程卻是相似的,也就是說這部分代碼是可以復(fù)用簡化編寫的。
      2. 在開發(fā)REST API的視圖中,雖然每個(gè)視圖具體操作的數(shù)據(jù)不同,但增、刪、改、查的實(shí)現(xiàn)流程基本套路化,所以這部分代碼也是可以復(fù)用簡化編寫的:
        • :校驗(yàn)請求數(shù)據(jù) -> 執(zhí)行反序列化過程 -> 保存數(shù)據(jù)庫 -> 將保存的對象序列化并返回
        • :判斷要?jiǎng)h除的數(shù)據(jù)是否存在 -> 執(zhí)行數(shù)據(jù)庫刪除
        • :判斷要修改的數(shù)據(jù)是否存在 -> 校驗(yàn)請求的數(shù)據(jù) -> 執(zhí)行反序列化過程 -> 保存數(shù)據(jù)庫 -> 將保存的對象序列化并返回
        • :查詢數(shù)據(jù)庫 -> 將數(shù)據(jù)序列化并返回


      Django REST framework可以幫助我們簡化上述兩部分的代碼編寫,大大提高REST API的開發(fā)速度。

       

      認(rèn)識(shí)Django REST framework

      Django REST framework 框架是一個(gè)用于構(gòu)建Web API 的強(qiáng)大而又靈活的工具。

      通常簡稱為DRF框架 或 REST framework。

      DRF框架是建立在Django框架基礎(chǔ)之上,由Tom Christie大牛二次開發(fā)的開源項(xiàng)目。

      特點(diǎn)

      • 提供了定義序列化器Serializer的方法,可以快速根據(jù) Django ORM 或者其它庫自動(dòng)序列化/反序列化;
      • 提供了豐富的類視圖、Mixin擴(kuò)展類,簡化視圖的編寫;
      • 豐富的定制層級(jí):函數(shù)視圖、類視圖、視圖集合到自動(dòng)生成 API,滿足各種需要;
      • 多種身份認(rèn)證和權(quán)限認(rèn)證方式的支持;
      • 內(nèi)置了限流系統(tǒng);
      • 直觀的 API web 界面;
      • 可擴(kuò)展性,插件豐富

       

      2. DRF工程搭建


      2.1 環(huán)境安裝與配置

      DRF需要以下依賴:

      • Python (3.6,3.7,3.8,3.9)
      • Django (2.0,3.0,3.2.11)

       

      DRF是以Django擴(kuò)展應(yīng)用的方式提供的,所以我們可以直接利用已有的Django環(huán)境而無需從新創(chuàng)建。(若沒有Django環(huán)境,需要先創(chuàng)建環(huán)境安裝Django)

       

      1. 安裝DRF

      pip install djangorestframework

       

      2. 添加rest_framework應(yīng)用

      我們利用在Django框架學(xué)習(xí)中創(chuàng)建的demo工程,在settings.pyINSTALLED_APPS中添加'rest_framework'。

      INSTALLED_APPS = [
          ...
          'rest_framework',
      ]

      接下來就可以使用DRF進(jìn)行開發(fā)了。

       

      2.2 見識(shí)DRF的魅力

       

      1. 創(chuàng)建序列化器

      在booktest應(yīng)用中新建serializers.py用于保存該應(yīng)用的序列化器。

      創(chuàng)建一個(gè)BookInfoSerializer用于序列化與反序列化。

      class BookInfoSerializer(serializers.ModelSerializer):
          """圖書數(shù)據(jù)序列化器"""
          class Meta:
              model = BookInfo
              fields = '__all__'
      • model 指明該序列化器處理的數(shù)據(jù)字段從模型類BookInfo參考生成
      • fields 指明該序列化器包含模型類中的哪些字段,'__all__'指明包含所有字段

       

      2. 編寫視圖

      在booktest應(yīng)用的views.py中創(chuàng)建視圖BookInfoViewSet,這是一個(gè)視圖集合。

      from rest_framework.viewsets import ModelViewSet
      from .serializers import BookInfoSerializer
      from .models import BookInfo
      
      class BookInfoViewSet(ModelViewSet):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      • queryset 指明該視圖集在查詢數(shù)據(jù)時(shí)使用的查詢集
      • serializer_class 指明該視圖在進(jìn)行序列化或反序列化時(shí)使用的序列化器

       

      3. 定義路由

      在booktest應(yīng)用的urls.py中定義路由信息。

      from . import views
      from rest_framework.routers import DefaultRouter
      
      urlpatterns = [
          ...
      ]
      
      router = DefaultRouter()  # 可以處理視圖的路由器
      router.register(r'books', views.BookInfoViewSet)  # 向路由器中注冊視圖集
      
      urlpatterns += router.urls  # 將路由器中的所以路由信息追到到django的路由列表中

       

      4. 運(yùn)行測試

      運(yùn)行當(dāng)前程序(與運(yùn)行Django一樣)

      python manage.py runserver

      在瀏覽器中輸入網(wǎng)址127.0.0.1:8000,可以看到DRF提供的API Web瀏覽頁面:


      1)點(diǎn)擊鏈接127.0.0.1:8000/books/ 可以訪問獲取所有數(shù)據(jù)的接口,呈現(xiàn)如下頁面:


      2)在頁面底下表單部分填寫圖書信息,可以訪問添加新圖書的接口,保存新書:


      點(diǎn)擊POST后,返回如下頁面信息:


      3)在瀏覽器中輸入網(wǎng)址127.0.0.1:8000/books/1/,可以訪問獲取單一圖書信息的接口(id為1的圖書),呈現(xiàn)如下頁面:


      4)在頁面底部表單中填寫圖書信息,可以訪問修改圖書的接口


      點(diǎn)擊PUT,返回如下頁面信息:


      5)點(diǎn)擊DELETE按鈕,可以訪問刪除圖書的接口

      返回,如下頁面:

       

      3.Serializer序列化器

      序列化器的作用:

      1. 進(jìn)行數(shù)據(jù)的校驗(yàn)
      2. 對數(shù)據(jù)對象進(jìn)行轉(zhuǎn)換

      3.1 定義方法

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

      例如,我們已有了一個(gè)數(shù)據(jù)庫模型類BookInfo

      class BookInfo(models.Model):
          btitle   = models.CharField(max_length  = 20 , verbose_name  = '名稱' )
          bpub_date   = models.DateField(verbose_name  = '發(fā)布日期' , null  = True )
          bread   = models.IntegerField(default  = 0 , verbose_name  = '閱讀量' )
          bcomment   = models.IntegerField(default  = 0 , verbose_name  = '評(píng)論量' )
          image   = models.ImageField(upload_to  = 'booktest' , verbose_name  = '圖片' , null  = True )

        

      為這個(gè)模型類提供一個(gè)序列化器,可以定義如下:

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          id = serializers.IntegerField(label = 'ID' , read_only = True )
          btitle  = serializers.CharField(label = '名稱' , max_length = 20 )
          bpub_date  = serializers.DateField(label = '發(fā)布日期' , required = False )
          bread  = serializers.IntegerField(label = '閱讀量' , required = False )
          bcomment  = serializers.IntegerField(label = '評(píng)論量' , required = False )
          image  = serializers.ImageField(label = '圖片' , required = False )

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

       

      2. 字段與選項(xiàng)

      字段字段構(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)
      正則字段,驗(yàn)證正則模式 [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ù)點(diǎn)位置
      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=)

       

      選項(xiàng)參數(shù):

      參數(shù)名稱作用
      max_length 最大長度
      min_length 最小長度
      allow_blank 是否允許為空
      trim_whitespace 是否截?cái)嗫瞻鬃址?/td>
      max_value 最大值
      min_value 最小值

       

      通用參數(shù):

      參數(shù)名稱說明
      read_only

      表明該字段僅用于序列化輸出,默認(rèn)False

      字段只讀,默認(rèn)值為False。只讀字段只會(huì)包含序列化輸出中,創(chuàng)建修改對象不會(huì)包含該字段【設(shè)置序列化字段的只讀屬性】

      write_only

      表明該字段僅用于反序列化輸入,默認(rèn)False

      字段只寫,默認(rèn)值為False 和 read_only 相反,序列化時(shí)不包含,創(chuàng)建修改對象必須包含該字段【設(shè)置序列化字段的編輯屬性】

      required

      表明該字段在反序列化時(shí)必須輸入,默認(rèn)True

      字段必須,默認(rèn)是True 必須字段在創(chuàng)建修改對象時(shí)必須包含,否則拋出異常。當(dāng)設(shè)置為False時(shí),在創(chuàng)建修改對象可以不用包含該字段【設(shè)置序列化字段的數(shù)據(jù)是否為空,默認(rèn)值為True】

      default

      反序列化時(shí)使用的默認(rèn)值

      默認(rèn)值。如果一個(gè)字段設(shè)置了默認(rèn)值,那么在反序列時(shí),如果沒有提供該子彈,則使用默認(rèn)進(jìn)行填充,在進(jìn)行局部更新時(shí),default 不會(huì)應(yīng)用,因?yàn)榫植扛聲r(shí),只有更新的字段會(huì)被校驗(yàn)和返回。還可以設(shè)置一個(gè)函數(shù)或者一個(gè)可調(diào)用對象。可以設(shè)置為一個(gè)函數(shù)或其他可調(diào)用對象,會(huì)使用調(diào)用后的結(jié)果填充。調(diào)用時(shí),它不接受任何參數(shù),如果可調(diào)用對象有一個(gè)requires_context = True屬性,那么序列化字段會(huì)被當(dāng)做參數(shù)傳入

      allow_null

      表明該字段是否允許傳入None,默認(rèn)False

      如果將None傳遞給序列化器字段,將引發(fā)錯(cuò)誤。如果None應(yīng)該被認(rèn)為是一個(gè)有效值,則將該關(guān)鍵字參數(shù)設(shè)置為True 注意:將該參數(shù)設(shè)置為Ture將意味著序列化輸出的默認(rèn)值是None,但并不意味著輸入反序列化是默認(rèn)的。默認(rèn)值是False

      validators 自定義數(shù)據(jù)驗(yàn)證規(guī)則,以列表格式表示,列表元素為數(shù)據(jù)驗(yàn)證的函數(shù)名
      error_messages 包含錯(cuò)誤編號(hào)與錯(cuò)誤信息的字典
      label 一個(gè)文本字符串。可以用作HTML表單字段或其他描述元素的字段名
      help_text 可以在HTML表單子彈活其他描述元素中用作字段描述的文本字符串
      source 將用于填充字段的屬性的名稱。可以是一個(gè)接受self參數(shù)的方法(source='方法名')也可以是屬性(source='channel.name')
      initial 設(shè)置序列化的初始值
      style 以字典格式化表示,控制模板引擎如何渲染序列化字段

       

      3. 創(chuàng)建Serializer對象

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

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

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

      說明:

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

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

      3.2序列化使用

      1 基本使用

      1) 先查詢出一個(gè)圖書對象

      from booktest.models import BookInfo
      
      book = BookInfo.objects.get(id=2)

      2) 構(gòu)造序列化器對象

      from booktest.serializers import BookInfoSerializer
      
      serializer = BookInfoSerializer(book)

      3)獲取序列化數(shù)據(jù)

      通過data屬性可以獲取序列化后的數(shù)據(jù)

      serializer.data
      # {'id': 2, 'btitle': '天龍八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None}

      4)如果要被序列化的是包含多條數(shù)據(jù)的查詢集QuerySet,可以通過添加many=True參數(shù)補(bǔ)充說明

      book_qs = BookInfo.objects.all()
      serializer = BookInfoSerializer(book_qs, many=True)
      serializer.data
      # [OrderedDict([('id', 2), ('btitle', '天龍八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40), ('image', N]), OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image'ne)]), OrderedDict([('id', 4), ('btitle', '雪山飛狐'), ('bpub_date', '1987-11-11'), ('bread', 58), ('bcomment', 24), ('ima None)]), OrderedDict([('id', 5), ('btitle', '西游記'), ('bpub_date', '1988-01-01'), ('bread', 10), ('bcomment', 10), ('im', 'booktest/xiyouji.png')])]

      2 關(guān)聯(lián)對象嵌套序列化

      如果需要序列化的數(shù)據(jù)中包含有其他關(guān)聯(lián)對象,則對關(guān)聯(lián)對象數(shù)據(jù)的序列化需要指明。

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

      我們先定義HeroInfoSerialzier除外鍵字段外的其他部分

      class HeroInfoSerializer(serializers.Serializer):
          """英雄數(shù)據(jù)序列化器"""
          GENDER_CHOICES = (
              (0, 'male'),
              (1, 'female')
          )
          id = serializers.IntegerField(label='ID', read_only=True)
          hname = serializers.CharField(label='名字', max_length=20)
          hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性別', required=False)
          hcomment = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)

      對于關(guān)聯(lián)字段,可以采用以下幾種方式:

      1) PrimaryKeyRelatedField

      此字段將被序列化為關(guān)聯(lián)對象的主鍵。

      hbook = serializers.PrimaryKeyRelatedField(label='圖書', read_only=True)
      或
      hbook = serializers.PrimaryKeyRelatedField(label='圖書', queryset=BookInfo.objects.all())

      指明字段時(shí)需要包含read_only=True或者queryset參數(shù):

      • 包含read_only=True參數(shù)時(shí),該字段將不能用作反序列化使用
      • 包含queryset參數(shù)時(shí),將被用作反序列化時(shí)參數(shù)校驗(yàn)使用

      使用效果:

      from booktest.serializers import HeroInfoSerializer
      from booktest.models import HeroInfo
      hero = HeroInfo.objects.get(id=6)
      serializer = HeroInfoSerializer(hero)
      serializer.data
      # {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': 2}

      2)使用關(guān)聯(lián)對象的序列化器

      hbook = BookInfoSerializer()

      使用效果

      {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': OrderedDict([('id', 2), ('btitle', '天龍八部')te', '1986-07-24'), ('bread', 36), ('bcomment', 40), ('image', None)])}

      3) StringRelatedField

      此字段將被序列化為關(guān)聯(lián)對象的字符串表示方式(即__str__方法的返回值)

      hbook = serializers.StringRelatedField(label='圖書')

      使用效果

      {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': '天龍八部'}

      4)HyperlinkedRelatedField

      此字段將被序列化為獲取關(guān)聯(lián)對象數(shù)據(jù)的接口鏈接

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

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

      使用效果

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

      我們暫時(shí)還沒有定義視圖,此方式不再演示。

      5)SlugRelatedField

      此字段將被序列化為關(guān)聯(lián)對象的指定字段數(shù)據(jù)

      hbook = serializers.SlugRelatedField(label='圖書', read_only=True, slug_field='bpub_date')

      slug_field指明使用關(guān)聯(lián)對象的哪個(gè)字段

      使用效果

      {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': datetime.date(1986, 7, 24)}

      6) 重寫to_representation方法

      序列化器的每個(gè)字段實(shí)際都是由該字段類型的to_representation方法決定格式的,可以通過重寫該方法來決定格式。

      注意,to_representations方法不僅局限在控制關(guān)聯(lián)對象格式上,適用于各個(gè)序列化器字段類型。

      自定義一個(gè)新的關(guān)聯(lián)字段:

      class BookRelateField(serializers.RelatedField):
          """自定義用于處理圖書的字段"""
          def to_representation(self, value):
              return 'Book: %d %s' % (value.id, value.btitle)

      指明hbook為BookRelateField類型

      hbook = BookRelateField(read_only=True)

      使用效果

      {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': 'Book: 2 天龍八部'}

      3 many參數(shù)

      如果關(guān)聯(lián)的對象數(shù)據(jù)不是只有一個(gè),而是包含多個(gè)數(shù)據(jù),如想序列化圖書BookInfo數(shù)據(jù),每個(gè)BookInfo對象關(guān)聯(lián)的英雄HeroInfo對象可能有多個(gè),此時(shí)關(guān)聯(lián)字段類型的指明仍可使用上述幾種方式,只是在聲明關(guān)聯(lián)字段時(shí),多補(bǔ)充一個(gè)many=True參數(shù)即可。

      此處僅拿PrimaryKeyRelatedField類型來舉例,其他相同。

      在BookInfoSerializer中添加關(guān)聯(lián)字段:

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          id = serializers.IntegerField(label='ID', read_only=True)
          btitle = serializers.CharField(label='名稱', max_length=20)
          bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
          bread = serializers.IntegerField(label='閱讀量', required=False)
          bcomment = serializers.IntegerField(label='評(píng)論量', required=False)
          image = serializers.ImageField(label='圖片', required=False)
          heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)  # 新增

      使用效果:

      from booktest.serializers import BookInfoSerializer
      from booktest.models import BookInfo
      book = BookInfo.objects.get(id=2)
      serializer = BookInfoSerializer(book)
      serializer.data
      # {'id': 2, 'btitle': '天龍八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image':

      3.3反序列化使用

      1. 驗(yàn)證

      使用序列化器進(jìn)行反序列化時(shí),需要對數(shù)據(jù)進(jìn)行驗(yàn)證后,才能獲取驗(yàn)證成功的數(shù)據(jù)或保存成模型類對象。

      在獲取反序列化的數(shù)據(jù)前,必須調(diào)用is_valid()方法進(jìn)行驗(yàn)證,驗(yàn)證成功返回True,否則返回False。

      驗(yàn)證失敗,可以通過序列化器對象的errors屬性獲取錯(cuò)誤信息,返回字典,包含了字段和字段的錯(cuò)誤。如果是非字段錯(cuò)誤,可以通過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯(cuò)誤字典中的鍵名。

      驗(yàn)證成功,可以通過序列化器對象的validated_data屬性獲取數(shù)據(jù)。

      在定義序列化器時(shí),指明每個(gè)字段的序列化類型和選項(xiàng)參數(shù),本身就是一種驗(yàn)證行為。

      如我們前面定義過的BookInfoSerializer

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          id = serializers.IntegerField(label='ID', read_only=True)
          btitle = serializers.CharField(label='名稱', max_length=20)
          bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
          bread = serializers.IntegerField(label='閱讀量', required=False)
          bcomment = serializers.IntegerField(label='評(píng)論量', required=False)
          image = serializers.ImageField(label='圖片', required=False)

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

      from booktest.serializers import BookInfoSerializer
      data = {'bpub_date': 123}
      serializer = BookInfoSerializer(data=data)
      serializer.is_valid()  # 返回False
      serializer.errors
      # {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
      serializer.validated_data  # {}
      
      data = {'btitle': 'python'}
      serializer = BookInfoSerializer(data=data)
      serializer.is_valid()  # True
      serializer.errors  # {}
      serializer.validated_data  #  OrderedDict([('btitle', 'python')])

      is_valid()方法還可以在驗(yàn)證失敗時(shí)拋出異常serializers.ValidationError,可以通過傳遞raise_exception=True參數(shù)開啟,REST framework接收到此異常,會(huì)向前端返回HTTP 400 Bad Request響應(yīng)。

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

      如果覺得這些還不夠,需要再補(bǔ)充定義驗(yàn)證行為,可以使用以下三種方法:

      1)validators

      在字段中添加validators選項(xiàng)參數(shù),也可以補(bǔ)充驗(yàn)證行為,如

      
      def about_django(value):
          if 'django' not in value.lower():
              raise serializers.ValidationError("圖書不是關(guān)于Django的")
      
      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          id = serializers.IntegerField(label='ID', read_only=True)
          btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
          bpub_date = serializers.DateField(label='發(fā)布日期', required=False)
          bread = serializers.IntegerField(label='閱讀量', required=False)
          bcomment = serializers.IntegerField(label='評(píng)論量', required=False)
          image = serializers.ImageField(label='圖片', required=False)

      測試:

      from 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')]}

      2)validate_<field_name>

      <field_name>字段進(jìn)行驗(yàn)證,如

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          ...
      
          def validate_btitle(self, value):
              if 'django' not in value.lower():
                  raise serializers.ValidationError("圖書不是關(guān)于Django的")
              return value

      測試

      from 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)validate

      在序列化器中需要同時(shí)對多個(gè)字段進(jìn)行比較驗(yàn)證時(shí),可以定義validate方法來驗(yàn)證,如

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          ...
      
          def validate(self, attrs):
              bread = attrs['bread']
              bcomment = attrs['bcomment']
              if bread < bcomment:
                  raise serializers.ValidationError('閱讀量小于評(píng)論量')
              return attrs

      測試

      from booktest.serializers import BookInfoSerializer
      data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
      s = BookInfoSerializer(data=data)
      s.is_valid()  # False
      s.errors
      #  {'non_field_errors': [ErrorDetail(string='閱讀量小于評(píng)論量', code='invalid')]}

      REST framework提供的validators:

      • UniqueValidator

        單字段唯一,如

        from rest_framework.validators import UniqueValidator
        
        slug = SlugField(
            max_length=100,
            validators=[UniqueValidator(queryset=BlogPost.objects.all())]
        )
      • UniqueTogetherValidation

        聯(lián)合唯一,如

        from rest_framework.validators import UniqueTogetherValidator
        
        class ExampleSerializer(serializers.Serializer):
            # ...
            class Meta:
                validators = [
                    UniqueTogetherValidator(
                        queryset=ToDoItem.objects.all(),
                        fields=('list', 'position')
                    )
                ]

      2. 保存

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

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          ...
      
          def create(self, validated_data):
              """新建"""
              return BookInfo(**validated_data)
      
          def update(self, instance, validated_data):
              """更新,instance為要更新的對象實(shí)例"""
              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)
              return instance

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

      class BookInfoSerializer(serializers.Serializer):
          """圖書數(shù)據(jù)序列化器"""
          ...
      
          def create(self, validated_data):
              """新建"""
              return BookInfo.objects.create(**validated_data)
      
          def update(self, instance, validated_data):
              """更新,instance為要更新的對象實(shí)例"""
              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

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

      book = serializer.save()

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

      from db.serializers import BookInfoSerializer
      data = {'btitle': '封神演義'}
      serializer = BookInfoSerializer(data=data)
      serializer.is_valid()  # True
      serializer.save()  # <BookInfo: 封神演義>
      
      from db.models import BookInfo
      book = BookInfo.objects.get(id=2)
      data = {'btitle': '倚天劍'}
      serializer = BookInfoSerializer(book, data=data)
      serializer.is_valid()  # True
      serializer.save()  # <BookInfo: 倚天劍>
      book.btitle  # '倚天劍'

      兩點(diǎn)說明:

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

      serializer.save(owner=request.user)

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

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

      3.4 模型類序列化器ModelSerializer

      如果我們想要使用序列化器對應(yīng)的是Django的模型類,DRF為我們提供了ModelSerializer模型類序列化器來幫助我們快速創(chuàng)建一個(gè)Serializer類。

      ModelSerializer與常規(guī)的Serializer相同,但提供了:

      • 基于模型類自動(dòng)生成一系列字段
      • 基于模型類自動(dòng)為Serializer生成validators,比如unique_together
      • 包含默認(rèn)的create()和update()的實(shí)現(xiàn)

      1. 定義

      比如我們創(chuàng)建一個(gè)BookInfoSerializer

      class BookInfoSerializer(serializers.ModelSerializer):
          """圖書數(shù)據(jù)序列化器"""
          class Meta:
              model = BookInfo
              fields = '__all__'
      • model 指明參照哪個(gè)模型類
      • fields 指明為模型類的哪些字段生成

      我們可以在python manage.py shell中查看自動(dòng)生成的BookInfoSerializer的具體實(shí)現(xiàn)

      >>> from booktest.serializers import BookInfoSerializer
      >>> serializer = BookInfoSerializer()
      >>> serializer
      BookInfoSerializer():
          id = IntegerField(label='ID', read_only=True)
          btitle = CharField(label='名稱', max_length=20)
          bpub_date = DateField(allow_null=True, label='發(fā)布日期', required=False)
          bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
          bcomment = IntegerField(label='評(píng)論量', max_value=2147483647, min_value=-2147483648, required=False)
          image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)

      2. 指定字段

      1) 使用fields來明確字段,__all__表名包含所有字段,也可以寫明具體哪些字段,如

      class BookInfoSerializer(serializers.ModelSerializer):
          """圖書數(shù)據(jù)序列化器"""
          class Meta:
              model = BookInfo
              fields = ('id', 'btitle', 'bpub_date')

      2) 使用exclude可以明確排除掉哪些字段

      class BookInfoSerializer(serializers.ModelSerializer):
          """圖書數(shù)據(jù)序列化器"""
          class Meta:
              model = BookInfo
              exclude = ('image',)

      3) 默認(rèn)ModelSerializer使用主鍵作為關(guān)聯(lián)字段,但是我們可以使用depth來簡單的生成嵌套表示,depth應(yīng)該是整數(shù),表明嵌套的層級(jí)數(shù)量。如:

      class HeroInfoSerializer2(serializers.ModelSerializer):
          class Meta:
              model = HeroInfo
              fields = '__all__'
              depth = 1

      形成的序列化器如下:

      HeroInfoSerializer():
          id = IntegerField(label='ID', read_only=True)
          hname = CharField(label='名稱', max_length=20)
          hgender = ChoiceField(choices=((0, 'male'), (1, 'female')), label='性別', required=False, validators=[<django.core.valators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
          hcomment = CharField(allow_null=True, label='描述信息', max_length=200, required=False)
          hbook = NestedSerializer(read_only=True):
              id = IntegerField(label='ID', read_only=True)
              btitle = CharField(label='名稱', max_length=20)
              bpub_date = DateField(allow_null=True, label='發(fā)布日期', required=False)
              bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=-2147483648, required=False)
              bcomment = IntegerField(label='評(píng)論量', max_value=2147483647, min_value=-2147483648, required=False)
              image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)

      4) 顯示指明字段,如:

      class HeroInfoSerializer(serializers.ModelSerializer):
          hbook = BookInfoSerializer()
      
          class Meta:
              model = HeroInfo
              fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')

      5) 指明只讀字段

      可以通過read_only_fields指明只讀字段,即僅用于序列化輸出的字段

      class BookInfoSerializer(serializers.ModelSerializer):
          """圖書數(shù)據(jù)序列化器"""
          class Meta:
              model = BookInfo
              fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
              read_only_fields = ('id', 'bread', 'bcomment')

      3. 添加額外參數(shù)

      我們可以使用extra_kwargs參數(shù)為ModelSerializer添加或修改原有的選項(xiàng)參數(shù)

      class BookInfoSerializer(serializers.ModelSerializer):
          """圖書數(shù)據(jù)序列化器"""
          class Meta:
              model = BookInfo
              fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
              extra_kwargs = {
                  'bread': {'min_value': 0, 'required': True},
                  'bcomment': {'min_value': 0, 'required': True},
              }
      
      # BookInfoSerializer():
      #    id = IntegerField(label='ID', read_only=True)
      #    btitle = CharField(label='名稱', max_length=20)
      #    bpub_date = DateField(allow_null=True, label='發(fā)布日期', required=False)
      #    bread = IntegerField(label='閱讀量', max_value=2147483647, min_value=0, required=True)
      #    bcomment = IntegerField(label='評(píng)論量', max_value=2147483647, min_value=0, required=True)

       

       

      4.視圖

      Django REST framwork 提供的視圖的主要作用:

      • 控制序列化器的執(zhí)行(檢驗(yàn)、保存、轉(zhuǎn)換數(shù)據(jù))
      • 控制數(shù)據(jù)庫查詢的執(zhí)行

      4.1Request 與 Response

      1. Request

      REST framework 傳入視圖的request對象不再是Django默認(rèn)的HttpRequest對象,而是REST framework提供的擴(kuò)展了HttpRequest類的Request類的對象。

      REST framework 提供了Parser解析器,在接收到請求后會(huì)自動(dòng)根據(jù)Content-Type指明的請求數(shù)據(jù)類型(如JSON、表單等)將請求數(shù)據(jù)進(jìn)行parse解析,解析為類字典對象保存到Request對象中。

      Request對象的數(shù)據(jù)是自動(dòng)根據(jù)前端發(fā)送數(shù)據(jù)的格式進(jìn)行解析之后的結(jié)果。

      無論前端發(fā)送的哪種格式的數(shù)據(jù),我們都可以以統(tǒng)一的方式讀取數(shù)據(jù)。

      常用屬性

      1).data

      request.data 返回解析之后的請求體數(shù)據(jù)。類似于Django中標(biāo)準(zhǔn)的request.POST和 request.FILES屬性,但提供如下特性:

      • 包含了解析之后的文件和非文件數(shù)據(jù)
      • 包含了對POST、PUT、PATCH請求方式解析后的數(shù)據(jù)
      • 利用了REST framework的parsers解析器,不僅支持表單類型數(shù)據(jù),也支持JSON數(shù)據(jù)

      2).query_params

      request.query_params與Django標(biāo)準(zhǔn)的request.GET相同,只是更換了更正確的名稱而已。

      2. Response

      rest_framework.response.Response

      REST framework提供了一個(gè)響應(yīng)類Response,使用該類構(gòu)造響應(yīng)對象時(shí),響應(yīng)的具體數(shù)據(jù)內(nèi)容會(huì)被轉(zhuǎn)換(render渲染)成符合前端需求的類型。

      REST framework提供了Renderer 渲染器,用來根據(jù)請求頭中的Accept(接收數(shù)據(jù)類型聲明)來自動(dòng)轉(zhuǎn)換響應(yīng)數(shù)據(jù)到對應(yīng)格式。如果前端請求中未進(jìn)行Accept聲明,則會(huì)采用默認(rèn)方式處理響應(yīng)數(shù)據(jù),我們可以通過配置來修改默認(rèn)響應(yīng)格式。

      REST_FRAMEWORK = {
          'DEFAULT_RENDERER_CLASSES': (  # 默認(rèn)響應(yīng)渲染類
              'rest_framework.renderers.JSONRenderer',  # json渲染器
              'rest_framework.renderers.BrowsableAPIRenderer',  # 瀏覽API渲染器
          )
      }
      

      構(gòu)造方式

      Response(data, status=None, template_name=None, headers=None, content_type=None)
      

      data數(shù)據(jù)不要是render處理之后的數(shù)據(jù),只需傳遞python的內(nèi)建類型數(shù)據(jù)即可,REST framework會(huì)使用renderer渲染器處理data

      data不能是復(fù)雜結(jié)構(gòu)的數(shù)據(jù),如Django的模型類對象,對于這樣的數(shù)據(jù)我們可以使用Serializer序列化器序列化處理后(轉(zhuǎn)為了Python字典類型)再傳遞給data參數(shù)。

      參數(shù)說明:

      • data: 為響應(yīng)準(zhǔn)備的序列化處理后的數(shù)據(jù);
      • status: 狀態(tài)碼,默認(rèn)200;
      • template_name: 模板名稱,如果使用HTMLRenderer 時(shí)需指明;
      • headers: 用于存放響應(yīng)頭信息的字典;
      • content_type: 響應(yīng)數(shù)據(jù)的Content-Type,通常此參數(shù)無需傳遞,REST framework會(huì)根據(jù)前端所需類型數(shù)據(jù)來設(shè)置該參數(shù)。

      常用屬性:

      1).data

      傳給response對象的序列化后,但尚未render處理的數(shù)據(jù)

      2).status_code

      狀態(tài)碼的數(shù)字

      3).content

      經(jīng)過render處理后的響應(yīng)數(shù)據(jù)

      3. 狀態(tài)碼

      為了方便設(shè)置狀態(tài)碼,REST framewrok在rest_framework.status模塊中提供了常用狀態(tài)碼常量。

      1)信息告知 - 1xx
      HTTP_100_CONTINUE
      HTTP_101_SWITCHING_PROTOCOLS
      
      2)成功 - 2xx
      HTTP_200_OK
      HTTP_201_CREATED
      HTTP_202_ACCEPTED
      HTTP_203_NON_AUTHORITATIVE_INFORMATION
      HTTP_204_NO_CONTENT
      HTTP_205_RESET_CONTENT
      HTTP_206_PARTIAL_CONTENT
      HTTP_207_MULTI_STATUS
      
      3)重定向 - 3xx
      HTTP_300_MULTIPLE_CHOICES
      HTTP_301_MOVED_PERMANENTLY
      HTTP_302_FOUND
      HTTP_303_SEE_OTHER
      HTTP_304_NOT_MODIFIED
      HTTP_305_USE_PROXY
      HTTP_306_RESERVED
      HTTP_307_TEMPORARY_REDIRECT
      
      4)客戶端錯(cuò)誤 - 4xx
      HTTP_400_BAD_REQUEST
      HTTP_401_UNAUTHORIZED
      HTTP_402_PAYMENT_REQUIRED
      HTTP_403_FORBIDDEN
      HTTP_404_NOT_FOUND
      HTTP_405_METHOD_NOT_ALLOWED
      HTTP_406_NOT_ACCEPTABLE
      HTTP_407_PROXY_AUTHENTICATION_REQUIRED
      HTTP_408_REQUEST_TIMEOUT
      HTTP_409_CONFLICT
      HTTP_410_GONE
      HTTP_411_LENGTH_REQUIRED
      HTTP_412_PRECONDITION_FAILED
      HTTP_413_REQUEST_ENTITY_TOO_LARGE
      HTTP_414_REQUEST_URI_TOO_LONG
      HTTP_415_UNSUPPORTED_MEDIA_TYPE
      HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
      HTTP_417_EXPECTATION_FAILED
      HTTP_422_UNPROCESSABLE_ENTITY
      HTTP_423_LOCKED
      HTTP_424_FAILED_DEPENDENCY
      HTTP_428_PRECONDITION_REQUIRED
      HTTP_429_TOO_MANY_REQUESTS
      HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
      HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
      
      5)服務(wù)器錯(cuò)誤 - 5xx
      HTTP_500_INTERNAL_SERVER_ERROR
      HTTP_501_NOT_IMPLEMENTED
      HTTP_502_BAD_GATEWAY
      HTTP_503_SERVICE_UNAVAILABLE
      HTTP_504_GATEWAY_TIMEOUT
      HTTP_505_HTTP_VERSION_NOT_SUPPORTED
      HTTP_507_INSUFFICIENT_STORAGE
      HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

      4.2視圖概覽

      REST framework 提供了眾多的通用視圖基類與擴(kuò)展類,以簡化視圖的編寫。

      視圖的繼承關(guān)系:

       

       

       

      視圖的方法與屬性:

       

       

       

      4.3視圖說明

      1. 兩個(gè)基類

      1)APIView

      rest_framework.views.APIView

      APIView是REST framework提供的所有視圖的基類,繼承自Django的View父類。

      APIViewView的不同之處在于:

      • 傳入到視圖方法中的是REST framework的Request對象,而不是Django的HttpRequeset對象;
      • 視圖方法可以返回REST framework的Response對象,視圖會(huì)為響應(yīng)數(shù)據(jù)設(shè)置(render)符合前端要求的格式;
      • 任何APIException異常都會(huì)被捕獲到,并且處理成合適的響應(yīng)信息;
      • 在進(jìn)行dispatch()分發(fā)前,會(huì)對請求進(jìn)行身份認(rèn)證、權(quán)限檢查、流量控制。
      支持定義的屬性:
      • authentication_classes 列表或元祖,身份認(rèn)證類
      • permissoin_classes 列表或元祖,權(quán)限檢查類
      • throttle_classes 列表或元祖,流量控制類

      APIView中仍以常規(guī)的類視圖定義方法來實(shí)現(xiàn)get() 、post() 或者其他請求方式的方法。

      舉例:

      from rest_framework.views import APIView
      from rest_framework.response import Response
      
      # url(r'^books/$', views.BookListView.as_view()),
      class BookListView(APIView):
          def get(self, request):
              books = BookInfo.objects.all()
              serializer = BookInfoSerializer(books, many=True)
              return Response(serializer.data)
      

      2)GenericAPIView

      rest_framework.generics.GenericAPIView

      繼承自APIVIew,主要增加了操作序列化器和數(shù)據(jù)庫查詢的方法,作用是為下面Mixin擴(kuò)展類的執(zhí)行提供方法支持。通常在使用時(shí),可搭配一個(gè)或多個(gè)Mixin擴(kuò)展類。

      提供的關(guān)于序列化器使用的屬性與方法

      • 屬性:

        • serializer_class 指明視圖使用的序列化器
      • 方法:

        • get_serializer_class(self)

          返回序列化器類,默認(rèn)返回serializer_class,可以重寫,例如:

          def get_serializer_class(self):
              if self.request.user.is_staff:
                  return FullAccountSerializer
              return BasicAccountSerializer
          
        • get_serializer(self, args, *kwargs)

          返回序列化器對象,主要用來提供給Mixin擴(kuò)展類使用,如果我們在視圖中想要獲取序列化器對象,也可以直接調(diào)用此方法。

          注意,該方法在提供序列化器對象的時(shí)候,會(huì)向序列化器對象的context屬性補(bǔ)充三個(gè)數(shù)據(jù):request、format、view,這三個(gè)數(shù)據(jù)對象可以在定義序列化器時(shí)使用。

          • request 當(dāng)前視圖的請求對象

          • view 當(dāng)前請求的類視圖對象

          • format 當(dāng)前請求期望返回的數(shù)據(jù)格式


      提供的關(guān)于數(shù)據(jù)庫查詢的屬性與方法

      • 屬性:

        • queryset 指明使用的數(shù)據(jù)查詢集
      • 方法:

        • get_queryset(self)

          返回視圖使用的查詢集,主要用來提供給Mixin擴(kuò)展類使用,是列表視圖與詳情視圖獲取數(shù)據(jù)的基礎(chǔ),默認(rèn)返回queryset屬性,可以重寫,例如:

          def get_queryset(self):
              user = self.request.user
              return user.accounts.all()
          
        • get_object(self)

          返回詳情視圖所需的模型類數(shù)據(jù)對象,主要用來提供給Mixin擴(kuò)展類使用。

          在試圖中可以調(diào)用該方法獲取詳情信息的模型類對象。

          若詳情訪問的模型類對象不存在,會(huì)返回404。

          該方法會(huì)默認(rèn)使用APIView提供的check_object_permissions方法檢查當(dāng)前對象是否有權(quán)限被訪問。

          舉例:

          # url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
          class BookDetailView(GenericAPIView):
              queryset = BookInfo.objects.all()
              serializer_class = BookInfoSerializer
          
              def get(self, request, pk):
                  book = self.get_object() # get_object()方法根據(jù)pk參數(shù)查找queryset中的數(shù)據(jù)對象
                  serializer = self.get_serializer(book)
                  return Response(serializer.data)
          

      其他可以設(shè)置的屬性

      • pagination_class 指明分頁控制類
      • filter_backends 指明過濾控制后端


      2. 五個(gè)擴(kuò)展類

      作用:

      提供了幾種后端視圖(對數(shù)據(jù)資源進(jìn)行曾刪改查)處理流程的實(shí)現(xiàn),如果需要編寫的視圖屬于這五種,則視圖可以通過繼承相應(yīng)的擴(kuò)展類來復(fù)用代碼,減少自己編寫的代碼量。

      這五個(gè)擴(kuò)展類需要搭配GenericAPIView父類,因?yàn)槲鍌€(gè)擴(kuò)展類的實(shí)現(xiàn)需要調(diào)用GenericAPIView提供的序列化器與數(shù)據(jù)庫查詢的方法。


      1)ListModelMixin

      列表視圖擴(kuò)展類,提供list(request, *args, **kwargs)方法快速實(shí)現(xiàn)列表視圖,返回200狀態(tài)碼。

      該Mixin的list方法會(huì)對數(shù)據(jù)進(jìn)行過濾和分頁。

      源代碼:

      class ListModelMixin(object):
          """
          List a queryset.
          """
          def list(self, request, *args, **kwargs):
              # 過濾
              queryset = self.filter_queryset(self.get_queryset())
              # 分頁
              page = self.paginate_queryset(queryset)
              if page is not None:
                  serializer = self.get_serializer(page, many=True)
                  return self.get_paginated_response(serializer.data)
              # 序列化
              serializer = self.get_serializer(queryset, many=True)
              return Response(serializer.data)
      

      舉例:

      from rest_framework.mixins import ListModelMixin
      
      class BookListView(ListModelMixin, GenericAPIView):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      
          def get(self, request):
              return self.list(request)
      


      2)CreateModelMixin

      創(chuàng)建視圖擴(kuò)展類,提供create(request, *args, **kwargs)方法快速實(shí)現(xiàn)創(chuàng)建資源的視圖,成功返回201狀態(tài)碼。

      如果序列化器對前端發(fā)送的數(shù)據(jù)驗(yàn)證失敗,返回400錯(cuò)誤。

      源代碼:

      class CreateModelMixin(object):
          """
          Create a model instance.
          """
          def create(self, request, *args, **kwargs):
              # 獲取序列化器
              serializer = self.get_serializer(data=request.data)
              # 驗(yàn)證
              serializer.is_valid(raise_exception=True)
              # 保存
              self.perform_create(serializer)
              headers = self.get_success_headers(serializer.data)
              return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
      
          def perform_create(self, serializer):
              serializer.save()
      
          def get_success_headers(self, data):
              try:
                  return {'Location': str(data[api_settings.URL_FIELD_NAME])}
              except (TypeError, KeyError):
                  return {}
      


      3) RetrieveModelMixin

      詳情視圖擴(kuò)展類,提供retrieve(request, *args, **kwargs)方法,可以快速實(shí)現(xiàn)返回一個(gè)存在的數(shù)據(jù)對象。

      如果存在,返回200, 否則返回404。

      源代碼:

      class RetrieveModelMixin(object):
          """
          Retrieve a model instance.
          """
          def retrieve(self, request, *args, **kwargs):
              # 獲取對象,會(huì)檢查對象的權(quán)限
              instance = self.get_object()
              # 序列化
              serializer = self.get_serializer(instance)
              return Response(serializer.data)
      

      舉例:

      class BookDetailView(RetrieveModelMixin, GenericAPIView):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      
          def get(self, request, pk):
              return self.retrieve(request)
      


      4)UpdateModelMixin

      更新視圖擴(kuò)展類,提供update(request, *args, **kwargs)方法,可以快速實(shí)現(xiàn)更新一個(gè)存在的數(shù)據(jù)對象。

      同時(shí)也提供partial_update(request, *args, **kwargs)方法,可以實(shí)現(xiàn)局部更新。

      成功返回200,序列化器校驗(yàn)數(shù)據(jù)失敗時(shí),返回400錯(cuò)誤。

      源代碼:

      class UpdateModelMixin(object):
          """
          Update a model instance.
          """
          def update(self, request, *args, **kwargs):
              partial = kwargs.pop('partial', False)
              instance = self.get_object()
              serializer = self.get_serializer(instance, data=request.data, partial=partial)
              serializer.is_valid(raise_exception=True)
              self.perform_update(serializer)
      
              if getattr(instance, '_prefetched_objects_cache', None):
                  # If 'prefetch_related' has been applied to a queryset, we need to
                  # forcibly invalidate the prefetch cache on the instance.
                  instance._prefetched_objects_cache = {}
      
              return Response(serializer.data)
      
          def perform_update(self, serializer):
              serializer.save()
      
          def partial_update(self, request, *args, **kwargs):
              kwargs['partial'] = True
              return self.update(request, *args, **kwargs)
      


      5)DestroyModelMixin

      刪除視圖擴(kuò)展類,提供destroy(request, *args, **kwargs)方法,可以快速實(shí)現(xiàn)刪除一個(gè)存在的數(shù)據(jù)對象。

      成功返回204,不存在返回404。

      源代碼:

      class DestroyModelMixin(object):
          """
          Destroy a model instance.
          """
          def destroy(self, request, *args, **kwargs):
              instance = self.get_object()
              self.perform_destroy(instance)
              return Response(status=status.HTTP_204_NO_CONTENT)
      
          def perform_destroy(self, instance):
              instance.delete()
      


      3. 幾個(gè)可用子類視圖

      1) CreateAPIView

      提供 post 方法

      繼承自: GenericAPIView、CreateModelMixin

      2)ListAPIView

      提供 get 方法

      繼承自:GenericAPIView、ListModelMixin

      3)RetrieveAPIView

      提供 get 方法

      繼承自: GenericAPIView、RetrieveModelMixin

      4)DestoryAPIView

      提供 delete 方法

      繼承自:GenericAPIView、DestoryModelMixin

      5)UpdateAPIView

      提供 put 和 patch 方法

      繼承自:GenericAPIView、UpdateModelMixin

      6)ListCreateAPIView

      提供 get、post方法

      繼承自: GenericAPIView、ListModelMixin、CreateModelMixin

      7)RetrieveUpdateAPIView

      提供 get、put、patch方法

      繼承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

      8)RetrieveUpdateDestoryAPIView

      提供 get、put、patch、delete方法

      繼承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin


      4.4視圖集ViewSet

      使用視圖集ViewSet,可以將一系列邏輯相關(guān)的動(dòng)作放到一個(gè)類中:

      • list() 提供一組數(shù)據(jù)
      • retrieve() 提供單個(gè)數(shù)據(jù)
      • create() 創(chuàng)建數(shù)據(jù)
      • update() 保存數(shù)據(jù)
      • destory() 刪除數(shù)據(jù)

      ViewSet視圖集類不再實(shí)現(xiàn)get()、post()等方法,而是實(shí)現(xiàn)動(dòng)作 action 如 list() 、create() 等。

      視圖集只在使用as_view()方法的時(shí)候,才會(huì)將action動(dòng)作與具體請求方式對應(yīng)上。如:

      class BookInfoViewSet(viewsets.ViewSet):
      
          def list(self, request):
              books = BookInfo.objects.all()
              serializer = BookInfoSerializer(books, many=True)
              return Response(serializer.data)
      
          def retrieve(self, request, pk=None):
              try:
                  books = BookInfo.objects.get(id=pk)
              except BookInfo.DoesNotExist:
                  return Response(status=status.HTTP_404_NOT_FOUND)
              serializer = BookInfoSerializer(books)
              return Response(serializer.data)
      

      在設(shè)置路由時(shí),我們可以如下操作

      urlpatterns = [
          url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
          url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
      ]
      


      1. 常用視圖集父類

      1) ViewSet

      繼承自APIViewViewSetMixin,作用也與APIView基本類似,提供了身份認(rèn)證、權(quán)限校驗(yàn)、流量管理等。

      ViewSet主要通過繼承ViewSetMixin來實(shí)現(xiàn)在調(diào)用as_view()時(shí)傳入字典(如{'get':'list'})的映射處理工作。

      在ViewSet中,沒有提供任何動(dòng)作action方法,需要我們自己實(shí)現(xiàn)action方法。

      2)GenericViewSet

      使用ViewSet通常并不方便,因?yàn)閘ist、retrieve、create、update、destory等方法都需要自己編寫,而這些方法與前面講過的Mixin擴(kuò)展類提供的方法同名,所以我們可以通過繼承Mixin擴(kuò)展類來復(fù)用這些方法而無需自己編寫。但是Mixin擴(kuò)展類依賴與GenericAPIView,所以還需要繼承GenericAPIView

      GenericViewSet就幫助我們完成了這樣的繼承工作,繼承自GenericAPIViewViewSetMixin,在實(shí)現(xiàn)了調(diào)用as_view()時(shí)傳入字典(如{'get':'list'})的映射處理工作的同時(shí),還提供了GenericAPIView提供的基礎(chǔ)方法,可以直接搭配Mixin擴(kuò)展類使用。

      舉例:

      from rest_framework import mixins
      from rest_framework.viewsets import GenericViewSet
      from rest_framework.decorators import action
      
      class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      

      url的定義

      urlpatterns = [
          url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
          url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
      ]
      

      3)ModelViewSet

      繼承自GenericViewSet,同時(shí)包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

      4)ReadOnlyModelViewSet

      繼承自GenericViewSet,同時(shí)包括了ListModelMixin、RetrieveModelMixin。


      2. 視圖集中定義附加action動(dòng)作

      在視圖集中,除了上述默認(rèn)的方法動(dòng)作外,還可以添加自定義動(dòng)作。

      添加自定義動(dòng)作需要使用rest_framework.decorators.action裝飾器。

      以action裝飾器裝飾的方法名會(huì)作為action動(dòng)作名,與list、retrieve等同。

      action裝飾器可以接收兩個(gè)參數(shù):

      • methods: 該action支持的請求方式,列表傳遞
      • detail: 表示是action中要處理的是否是視圖資源的對象(即是否通過url路徑獲取主鍵)
        • True 表示使用通過URL獲取的主鍵對應(yīng)的數(shù)據(jù)對象
        • False 表示不使用URL獲取主鍵

      舉例:

      from rest_framework import mixins
      from rest_framework.viewsets import GenericViewSet
      from rest_framework.decorators import action
      
      class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      
          # detail為False 表示不需要處理具體的BookInfo對象
          @action(methods=['get'], detail=False)
          def latest(self, request):
              """
              返回最新的圖書信息
              """
              book = BookInfo.objects.latest('id')
              serializer = self.get_serializer(book)
              return Response(serializer.data)
      
          # detail為True,表示要處理具體與pk主鍵對應(yīng)的BookInfo對象
          @action(methods=['put'], detail=True)
          def read(self, request, pk):
              """
              修改圖書的閱讀量數(shù)據(jù)
              """
              book = self.get_object()
              book.bread = request.data.get('read')
              book.save()
              serializer = self.get_serializer(book)
              return Response(serializer.data)
      

      url的定義

      urlpatterns = [
          url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
          url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
          url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
          url(r'^books/(?P<pk>\d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
      ]
      


      3. action屬性

      在視圖集中,我們可以通過action對象屬性來獲取當(dāng)前請求視圖集時(shí)的action動(dòng)作是哪個(gè)。

      例如:

      def get_serializer_class(self):
          if self.action == 'create':
              return OrderCommitSerializer
          else:
              return OrderDataSerializer
      


      4. 視圖集的繼承關(guān)系

       

       

       

       

      具體介紹可以查看 https://www.django-rest-framework.org/api-guide/fields/

       

       
      posted @ 2022-03-03 17:03  北京測試菜鳥  閱讀(186)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 非会员区试看120秒6次| 国产亚洲精品AA片在线爽| 国产熟女老阿姨毛片看爽爽| 亚洲国产超清无码专区| 久久久久久亚洲精品a片成人| 欧美一本大道香蕉综合视频| 中文字幕精品无码一区二区| 国语精品自产拍在线观看网站| 成全世界免费高清观看| 麻豆精产国品一二三区区| 91高清免费国产自产拍| 成人国产精品免费网站| 2020国产欧洲精品网站| 亚洲色最新高清AV网站| 亚洲天堂成人一区二区三区| 国产在线午夜不卡精品影院| 五十路丰满中年熟女中出| 日韩精品一区二区三区在| 亚洲av成人无码天堂| 久久av高潮av喷水av无码| 亚洲av无码牛牛影视在线二区 | 日韩在线观看 一区二区| 日韩高清国产中文字幕| 国产成人a在线观看视频免费| 亚洲精品tv久久久久久久久久 | 中文字幕日韩精品有码| 白丝乳交内射一二三区| 九九久久人妻精品一区色| 免费AV片在线观看网址| 国产午夜大地久久| 少妇撒尿一区二区在线视频| 亚洲国产精品成人无码区| 亚洲精品乱码久久久久久自慰| 国产精品一区二区三区黄| 亚洲人成色99999在线观看| www内射国产在线观看| 国内揄拍国内精品对久久| 亚洲综合成人av在线| 澎湖县| 亚洲天堂成人一区二区三区| 蜜臀av久久国产午夜|