七、DRF之視圖

寫在前面-->視圖回顧:

Django視圖的使用
  1. Django的函數(shù)視圖:

    注意這里的 request 和 response, 獲取數(shù)據(jù)很麻煩, 返回數(shù)據(jù)很麻煩

    # 一個函數(shù)視圖處理多種請求, 代碼可讀性與復(fù)用性都不佳皮迟。
    
    # 視圖函數(shù):注冊
    # url(r'^register/$', views.register, name='register'),
    
    def register(request):
        """處理注冊"""
    
        # 獲取請求方法搬泥,判斷是GET/POST請求
        if request.method == 'GET':
            # 處理GET請求,返回注冊頁面
            return render(request, 'register.html')
        else:
            # 處理POST請求伏尼,實現(xiàn)注冊邏輯
            return HttpResponse('這里實現(xiàn)注冊邏輯')
    

    注意: render(request對象, 模板文件路徑, 模板數(shù)據(jù)字典)

    ? 使用render,記得 第一個參數(shù) 需要寫<request>

  1. Django的類視圖:

    敲黑板: 這里 我們 第一次見到了 View

    要明確的是:

    1. 類視圖View 還是 使用的 Django的 原生 Request 和 Response, 所以 不好用
    2. 類視圖View, 提供了各種 get(), post(), put() , delete() 函數(shù)方法
    # 使用: 將視圖對應(yīng)的 <不同請求方式> 以類中的 <不同方法> 來區(qū)別定義忿檩。
    
    # 類視圖:注冊
    # url(r'^register/$', views.RegisterView.as_view(), name='register'),
    
    from django.views.generic import View
    
    class RegisterView(View):
        """類視圖:處理注冊"""
    
        def get(self, request):
            """處理GET請求,返回注冊頁面"""
            return render(request, 'register.html')
    
        def post(self, request):
            """處理POST請求爆阶,實現(xiàn)注冊邏輯"""
            return HttpResponse('這里實現(xiàn)注冊邏輯')
    

一燥透、APIView類視圖

1.1 APIView是DRF對View的擴展

與View區(qū)別:

  1. Request 對象 不一樣

  2. Response 對象 不一樣

  3. 任何APIException異常都會被捕獲到,并且處理成合適的響應(yīng)信息扰她;

  4. 在進行dispatch()分發(fā)前兽掰,會對請求進行身份認(rèn)證、權(quán)限檢查徒役、流量控制孽尽。

  5. 繼承了 View 的 get(), post(), put() , delete() 函數(shù)方法

  1. 關(guān)于Request對象

    1. 其將解析為類字典對象保存到Request對象中

    2. 獲取Request數(shù)據(jù)

    • request.data

      ? 1) 包含了對POST、PUT忧勿、PATCH請求方式解析后的數(shù)據(jù)(增加-更新-局部更新)

      ? 2) 相當(dāng)于 request.body (json數(shù)據(jù)獲取) + request.POST (post.form表單數(shù)據(jù)獲取)

    • request.query_params

    ? 與Django標(biāo)準(zhǔn)的request.GET相同

  2. 關(guān)于Response對象

    Response會根據(jù)請求頭中的Accept(接收數(shù)據(jù)類型聲明)來自動轉(zhuǎn)換響應(yīng)數(shù)據(jù)到對應(yīng)格式杉女。如果前端請求中未進行Accept聲明,則會采用默認(rèn)方式處理響應(yīng)數(shù)據(jù)鸳吸,我們可以通過配置來修改默認(rèn)響應(yīng)格式熏挎。

    • 構(gòu)造方式
    Response(data, status=None, template_name=None, headers=None, content_type=None)
    # data: 只需傳遞python的內(nèi)建類型數(shù)據(jù)即可, 不可是對象;
    # status: 狀態(tài)碼,默認(rèn)200晌砾;
    # template_name: 模板名稱坎拐,如果使用HTMLRenderer時需指明;
    # headers: 用于存放響應(yīng)頭信息的字典养匈;
    # content_type: 響應(yīng)數(shù)據(jù)的Content-Type哼勇,通常此參數(shù)無需傳遞,REST framework會根據(jù)前端所需類型數(shù)據(jù)來設(shè)置該參數(shù)呕乎。
    
    • 狀態(tài)碼
    # 1)信息告知 - 1xx
    # 2)成功 - 2xx
    # 3)重定向 - 3xx
    # 4)客戶端錯誤 - 4xx
    # 5)服務(wù)器錯誤 - 5xx
    

1.2 支持定義的屬性
  • authentication_classes列表或元祖积担,身份認(rèn)證類
  • permissoin_classes列表或元祖,權(quán)限檢查類
  • throttle_classes列表或元祖猬仁,流量控制類
1.3 代碼
# 在APIView中仍以常規(guī)的類視圖定義方法來實現(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)

二湿刽、GenericAPIView類視圖

2.1 GenericAPIView是對APIView的擴展

  • 繼承自APIVIew的烁,
  1. 增加了對于列表視圖詳情視圖可能用到的通用支持方法。
  2. 搭配一個或多個Mixin擴展類诈闺。
  3. 需要實現(xiàn)queryset屬性或者重寫get_queryset方法
2.1 屬性:
  • 列表視圖與詳情視圖通用:
    • queryset列表視圖的查詢集
    • serializer_class視圖使用的序列化器
  • 列表視圖使用:
    • pagination_class分頁控制類
    • filter_backends過濾控制后端
  • 詳情頁視圖使用:
    • lookup_field查詢單一數(shù)據(jù)庫對象時使用的條件字段撮躁,默認(rèn)為'pk'
    • lookup_url_kwarg查詢單一數(shù)據(jù)時URL中的參數(shù)關(guān)鍵字名稱,默認(rèn)與look_field相同
2.2 方法:
  • 列表視圖與詳情視圖通用:

    • get_queryset(self)

      返回視圖使用的查詢集买雾,是列表視圖與詳情視圖獲取數(shù)據(jù)的基礎(chǔ)把曼,默認(rèn)返回queryset屬性,可以重寫漓穿,例如:

      def get_queryset(self):
          user = self.request.user
          return user.accounts.all()
      
    • 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)

      返回序列化器對象叙赚,被其他視圖或擴展類使用,如果我們在視圖中想要獲取序列化器對象僚饭,可以直接調(diào)用此方法震叮。

      注意,在提供序列化器對象的時候鳍鸵,REST framework會向?qū)ο蟮腸ontext屬性補充三個數(shù)據(jù):request苇瓣、format、view偿乖,這三個數(shù)據(jù)對象可以在定義序列化器時使用击罪。

  • 詳情視圖使用:

    • get_object(self)返回詳情視圖所需的模型類數(shù)據(jù)對象,默認(rèn)使用lookup_field參數(shù)來過濾queryset贪薪。 在試圖中可以調(diào)用該方法獲取詳情信息的模型類對象媳禁。

      若詳情訪問的模型類對象不存在,會返回404画切。

      該方法會默認(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()
              serializer = self.get_serializer(book)
              return Response(serializer.data)
      

三、Mixin類視圖

  1. Mixin類 定義了一些 方法,
  2. 通過使用 GenericAPIView 提供的方法霍弹、屬性,
  3. 實現(xiàn) 列表和詳情頁的 快速實現(xiàn)
  1. ListModelMixin

    快速實現(xiàn)列表視圖毫别,返回200狀態(tài)碼。

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

    源代碼:

    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
    from rest_framework.generics import GenericAPIView
    
    class ListModelView(ListModelMixin,GenericAPIView):
    
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def get(self,request):
            return self.list(request)   # 使用 ListModelMixin 類的 list()方法
    
    
  1. CreateModelMixin

    快速實現(xiàn)創(chuàng)建資源的視圖拧烦,成功返回201狀態(tài)碼。

    如果序列化器對前端發(fā)送的數(shù)據(jù)驗證失敗钝计,返回400錯誤恋博。

    源代碼:

    class CreateModelMixin(object):
        """
        Create a model instance.
        """
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            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 {}
    

    舉例:

    from rest_framework.mixins import CreateModelMixin
    
    class ListModelView(CreateModelMixin,GenericAPIView):
        
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def post(self,request):
            return self.create(request) # 使用 CreateModelMixin 類的 create()方法
    
  1. RetrieveModelMixin

    快速實現(xiàn)返回一個存在的數(shù)據(jù)對象。

    如果存在私恬,返回200债沮, 否則返回404。

    源代碼:

    class RetrieveModelMixin(object):
        """
        Retrieve a model instance.
        """
        def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
    

    例如:

    from rest_framework.mixins import RetrieveModelMixin
    
    class ListModelView(RetrieveModelMixin,GenericAPIView):
        
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def get(self,request,pk):
    
            return self.retrieve(request)   # 使用 RetrieveModelMixin 類的 retrieve()方法
    
  2. UpdateModelMixin

    快速實現(xiàn)更新一個存在的數(shù)據(jù)對象本鸣。

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

    成功返回200荣德,序列化器校驗數(shù)據(jù)失敗時闷煤,返回400錯誤童芹。

    源代碼:

    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)
    

    舉例:

    from rest_framework.mixins import UpdateModelMixin
    
    class ListModelView(UpdateModelMixin,GenericAPIView):
        
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def put(self,request,pk):
          return  self.update(request)
    
  3. DestroyModelMixin

    快速實現(xiàn)刪除一個存在的數(shù)據(jù)對象。

    成功返回204鲤拿,不存在返回404假褪。

    源代碼:

    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)
    

    舉例:

    from rest_framework.mixins import DestroyModelMixin
    
    class ListModelView(DestroyModelMixin,GenericAPIView):
        
        queryset = BookInfo.objects.all()
        serializer_class = BookInfoSerializer
    
        def delete(self,request,pk):
            return self.destroy(request)
    

四、幾個可用子類視圖 ,

只不過是在繼承時 省略合并了(XX_ModelMixin,GenericAPIView)

1) CreateAPIView

提供 post 方法

繼承自: GenericAPIView近顷、CreateModelMixin

2)ListAPIView

提供 get 方法

繼承自:GenericAPIView生音、ListModelMixin

3)RetireveAPIView

提供 get 方法

繼承自: GenericAPIView、RetrieveModelMixin

4)DestroyAPIView

提供 delete 方法

繼承自:GenericAPIView窒升、DestroyModelMixin

5)UpdateAPIView

提供 put 和 patch 方法

繼承自:GenericAPIView缀遍、UpdateModelMixin

6)RetrieveUpdateAPIView

提供 get、put饱须、patch方法

繼承自: GenericAPIView域醇、RetrieveModelMixin、UpdateModelMixin

7)RetrieveUpdateDestroyAPIView

提供 get冤寿、put歹苦、patch、delete方法

繼承自:GenericAPIView督怜、RetrieveModelMixin殴瘦、UpdateModelMixin、DestroyModelMixin


六号杠、視圖集

6.1 ViewSet
  1. ViewSet類只是一種基于類的View蚪腋,繼承自APIView

  2. 它不提供任何方法處理程序(如get()orpost()),

  3. 而是提供諸如list()create()之類的操作姨蟋。

? 優(yōu)點:

  • 重復(fù)的邏輯可以合并成一個類屉凯。例如我們只需要指定queryset一次,它將用于多個視圖眼溶。
  • 通過使用路由器悠砚,我們不再需要處理自己的URL配置
6.2 GenericViewSet
6.3 ModelViewSet
6.4 路由Router

DefaultRouter與SimpleRouter的區(qū)別是:

? DefaultRouter會多附帶一個默認(rèn)的API根視圖,返回一個包含所有列表視圖的超鏈接響應(yīng)數(shù)據(jù)堂飞。

1) 創(chuàng)建router對象灌旧,并注冊視圖集,注冊語法為

# register(prefix, viewset,base_name)
# prefix 該視圖集的路由前綴
# viewset 視圖集
# base_name 路由名稱的前綴

from rest_framework import routers

router = routers.SimpleRouter()  
# router = routers.DefaultRouter  # (提供API根視圖)

router.register(r'books', BookViewSet, base_name='book')
  1. 添加路由數(shù)據(jù)
urlpatterns = [
    ...
]
urlpatterns += router.urls

# 或

urlpatterns = [
    ...
    url(r'^', include(router.urls))
]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绰筛,隨后出現(xiàn)的幾起案子枢泰,更是在濱河造成了極大的恐慌,老刑警劉巖铝噩,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件良狈,死亡現(xiàn)場離奇詭異据沈,居然都是意外死亡珊佣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門茄蚯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事∧庇遥” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵补箍,是天一觀的道長。 經(jīng)常有香客問我啸蜜,道長坑雅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任衬横,我火速辦了婚禮裹粤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜂林。我一直安慰自己遥诉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布噪叙。 她就那樣靜靜地躺著矮锈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睁蕾。 梳的紋絲不亂的頭發(fā)上苞笨,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音子眶,去河邊找鬼瀑凝。 笑死,一個胖子當(dāng)著我的面吹牛臭杰,可吹牛的內(nèi)容都是我干的粤咪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼渴杆,長吁一口氣:“原來是場噩夢啊……” “哼寥枝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起将塑,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤脉顿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后点寥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艾疟,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔽莱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弟疆。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖盗冷,靈堂內(nèi)的尸體忽然破棺而出怠苔,到底是詐尸還是另有隱情,我是刑警寧澤仪糖,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布柑司,位于F島的核電站,受9級特大地震影響锅劝,放射性物質(zhì)發(fā)生泄漏攒驰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一故爵、第九天 我趴在偏房一處隱蔽的房頂上張望玻粪。 院中可真熱鬧,春花似錦诬垂、人聲如沸劲室。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽很洋。三九已至,卻和暖如春晦鞋,著一層夾襖步出監(jiān)牢的瞬間蹲缠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工悠垛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留线定,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓确买,卻偏偏與公主長得像斤讥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子湾趾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容