視圖基類、視圖擴展類、GenericAPIView的視圖子類、視圖集基類ViewSet、action屬性、路由Routers

視圖前端

  2個視圖基類python

    APIView數據庫

    GenericAPIViewdjango

  5個試圖擴展類後端

    1)ListModelMixinapi

    2)CreateModelMixinapp

    3)RetrieveModelMixinpost

    4)UpdateModelMixin學習

    5)DestoryModelMixinfetch

  GenericAPIView的視圖子類

    1)CreateAPIView

    2)ListAPIView

    3)RetrieveAPIView

    4)DestoryAPIView

    5)UpdateAPIView

    6)RetrieveUpdateAPIView

    7)RetrieveUpdateDestoryAPIView

  視圖集ViewSet

    經常使用視圖集父類

      1)ViewSet

      2)GenericViewSet

      3)ModelViewSet

      4)ReadOnlyModelViewSet

    視圖集中定義附加action動做

    action屬性

路由Routers

  使用方法

  視圖集中附加action的聲明

  action屬性

 

 

視圖

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

  控制序列化器的執行(檢驗、保存、轉換數據)

  控制數據庫查詢的執行【數據庫的刪除/查詢代碼寫在視圖中,更新和添加寫在序列化器】

  REST framework 提供了衆多的通用視圖基類與擴展類,以簡化視圖的編寫。

2個視圖基類

APIView 

rest_framework.views.APIView

APIView是REST framework提供的全部視圖的基類,繼承自Django的View父類

drf的APIView與Django的View的不一樣之處在於:

  傳入到視圖方法中的是REST framework的Request對象,而不是Django的HttpRequest對象;

  視圖方法能夠返回REST framework的Request對象,視圖會爲響應數據設置(render)符合前端要求的格式;

  任何APIException異常都會被捕獲到,而且處理成合適的響應信息;

  重寫了as_view(),在進行dispatch()路由分發前,會對http請求進行身份認證、權限檢查、訪問流量控制。

   

支持定義的類屬性

  authentication_classes    列表或元組,身份認證類

  permission_classes    列表或元組,權限檢查類

  throttle_classes      列表或元組,流量控制類

在APIView中仍常以常規的類視圖定義方法來實現get()、post()或者其餘請求方式的方法

舉例:  

# Create your views here.
"""APIView是drf裏面提供的全部視圖類的父類
   APIView提供的功能/屬性/方法是最少的,因此使用APIView基本相似咱們使用django的View
"""
"""
GET   /students/ 獲取多個學生信息 
POST  /students/ 添加一個學生信息

GET    /students/<pk>/  獲取一個學生信息 
PUT    /students/<pk>/  修改一個學生信息
DELETE /students/<pk>/  刪除一個學生信息
"""
from rest_framework.views import APIView
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response
from rest_framework import status

class StudentAPIView(APIView):
    def get(self,request):
        # 1. 獲取學生信息的數據模型
        student_list = Student.objects.all()
        # 2. 調用序列化器
        serializer = StudentModelSerializer(instance=student_list, many=True)
        # 3. 返回數據
        return Response(serializer.data)

    def post(self,request):
        # 1. 調用序列化器對用戶提交的數據進行驗證
        serializer = StudentModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 2. 調用序列化器進行數據庫操做
        instance = serializer.save() # save()方法返回的是添加成功之後的模型對象

        serializer = StudentModelSerializer(instance=instance)

        # 3. 返回新增數據
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class Student2APIView(APIView):
    def get(self,request,pk):
        # 1. 根據pk獲取模型對象
        student = Student.objects.get(pk=pk)
        # 2. 序列化器轉換數據
        serializer = StudentModelSerializer(instance=student)
        # 3. 響應數據
        return Response(serializer.data)

    def put(self,request,pk):
        # 1. 經過pk查詢學生信息
        student = Student.objects.get(pk=pk)

        # 3. 調用序列化器對客戶端發送過來的數據進行驗證
        serializer = StudentModelSerializer(instance=student, data=request.data)
        serializer.is_valid(raise_exception=True)
        # 4. 保存數據
        instance = serializer.save()

        serializer = StudentModelSerializer(instance=instance)

        # 5. 返回結果
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        # 1. 經過pk查詢學生信息
        Student.objects.get(pk=pk).delete()
        return Response({"message":"ok"}, status=status.HTTP_204_NO_CONTENT)

  

GenericAPIView

  通用視圖類主要做用就是把視圖中的獨特的代碼抽取出來,讓視圖方法中的代碼更加通用,方便把通用代碼進行簡寫。   

rest_framework.generics.GenericAPIView

  繼承自APIView,主要增長了操做序列化器和數據庫查詢的類屬性,做用是爲下面的Minxin視圖擴展類的執行提供方法支持。一般在經常使用時,可搭配一個或多個Mixin擴展類。

提供的關於序列化器使用的屬性與方法:

  屬性:

    serializer_class 指明視圖使用的序列化器類。

  方法:

    get_serializer_class(self)

    當出現一個視圖類中調用多個序列化器時,那麼能夠經過條件判斷在get_serializer_class方法中經過返回不一樣的序列化器類名就可讓視圖方法執行不一樣的序列化器對象了。

  返回序列化器類,默認返回serializer_class,能夠重寫,例如:

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer

  get_serializer(self,args,*kwargs)

  返回序列化器對象,主要用來提供給Mixin擴展類使用,若是咱們在視圖中想要獲取序列化器對象,也能夠直接調用此方法。

  注意,該方法在提供序列化器對象的時候,會向序列化器對象的context屬性補充三個數據:request、format、view,這三個數據對象能夠在定義序列化器時使用。

  • request 當前視圖的請求對象

  • view 當前請求的類視圖對象

  • format 當前請求指望返回的數據格式

 

 

  屬性:

 

 

    queryset 指明使用的數據查詢集

 

 

  方法:

 

 

    get_queryset(self)

    返回視圖使用的查詢集,主要用來提供給Mixin擴展類使用,是列表視圖與詳情視圖獲取數據的基礎,默認返回queryset屬性,能夠重寫,例如:

 

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

    get_object(self)   

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

      在試圖中能夠調用該方法獲取詳情信息的模型類對象。

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

      該方法會默認使用APIView提供的check_object_permissions方法檢查當前對象是否有權限被訪問。

      舉例:

# 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()方法根據pk參數查找queryset中的數據對象
        serializer = self.get_serializer(book)
        return Response(serializer.data) 

其餘能夠設置的屬性:

 

  pagination_class 指明分頁控制類

 

 

  filter_backends 指明過濾控制後端

 

爲了方便學習上面的GenericAPIView通用視圖類,咱們新建一個子應用。

python manage.py startapp gen

  代碼:

    

from rest_framework.generics import GenericAPIView

from students.models import Student
from .serializers import StudentModelSerializer, StudentModel2Serializer
from rest_framework.response import Response

class StudentsGenericAPIView(GenericAPIView):
    # 本次視圖類中要操做的數據[必填]
    queryset = Student.objects.all()
    # 本次視圖類中要調用的默認序列化器[玄天]
    serializer_class = StudentModelSerializer

    def get(self, request):
        """獲取全部學生信息"""
        serializer = self.get_serializer(instance=self.get_queryset(), many=True)

        return Response(serializer.data)

    def post(self,request):

        data = request.data

        serializer = self.get_serializer(data=data)

        serializer.is_valid(raise_exception=True)

        instance = serializer.save()

        serializer = self.get_serializer(instance=instance)

        return Response(serializer.data)


class StudentGenericAPIView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get_serializer_class(self):
        """重寫獲取序列化器類的方法"""
        if self.request.method == "GET":
            return StudentModel2Serializer
        else:
            return StudentModelSerializer

    # 在使用GenericAPIView視圖獲取或操做單個數據時,視圖方法中的表明主鍵的參數最好是pk
    def get(self,request,pk):
        """獲取一條數據"""
        serializer = self.get_serializer(instance=self.get_object())

        return Response(serializer.data)

    def put(self,request,pk):

        data = request.data

        serializer = self.get_serializer(instance=self.get_object(),data=data)

        serializer.is_valid(raise_exception=True)

        serializer.save()

        serializer = self.get_serializer(instance=self.get_object())

        return Response(serializer.data)

  序列化器類:

from rest_framework import serializers

from students.models import Student

class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model= Student
        fields = "__all__"


class StudentModel2Serializer(serializers.ModelSerializer):
    class Meta:
        model= Student
        fields = ("name","class_null")

5個試圖擴展類

做用:

  提供了幾種後端視圖(對數據資源進行曾刪改查)處理流程的實現,若是須要編寫的視圖屬於這五種,則視圖能夠經過繼承相應的擴展類來複用代碼,減小本身編寫的代碼量。

  這五個擴展類須要搭配GenericAPIView父類,由於五個擴展類的實現須要調用GenericAPIView提供的序列化器與數據庫查詢的方法。

1)ListModelMixin

  列表視圖擴展類,提供list(request, *args, **kwargs)方法快速實現列表視圖,返回200狀態碼。

該Mixin的list方法會對數據進行過濾和分頁。

源代碼:

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

  建立視圖擴展類,提供create(request, *args, **kwargs)方法快速實現建立資源的視圖,成功返回201狀態碼。

若是序列化器對前端發送的數據驗證失敗,返回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 {}

3)RetrieveModelMixin  

詳情視圖擴展類,提供retrieve(request, *args, **kwargs)方法,能夠快速實現返回一個存在的數據對象。

若是存在,返回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)

  舉例:

class BookDetailView(RetrieveModelMixin, GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        return self.retrieve(request)

4)UpdateModelMixin

  更新視圖擴展類,提供update(request, *args, **kwargs)方法,能夠快速實現更新一個存在的數據對象。

同時也提供partial_update(request, *args, **kwargs)方法,能夠實現局部更新。

  成功返回200,序列化器校驗數據失敗時,返回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)

5)DestoryModelMixin

  刪除視圖擴展類,提供destroy(request, *args, **kwargs)方法,能夠快速實現刪除一個存在的數據對象。

成功返回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()

  使用GenericAPIView和視圖擴展類,實現api接口,代碼:

"""GenericAPIView結合視圖擴展類實現api接口"""
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class Students2GenericAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):
    # 本次視圖類中要操做的數據[必填]
    queryset = Student.objects.all()
    # 本次視圖類中要調用的默認序列化器[玄天]
    serializer_class = StudentModelSerializer

    def get(self, request):
        """獲取多個學生信息"""
        return self.list(request)

    def post(self,request):
        """添加學生信息"""
        return self.create(request)


from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student2GenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Student.objects.all()

    serializer_class = StudentModelSerializer

    # 在使用GenericAPIView視圖獲取或操做單個數據時,視圖方法中的表明主鍵的參數最好是pk
    def get(self,request,pk):
        """獲取一條數據"""
        return self.retrieve(request,pk)

    def put(self,request,pk):
        """更新一條數據"""
        return self.update(request,pk)

    def delete(self,request,pk):
        """刪除一條數據"""
        return self.destroy(request,pk)

GenericAPIView的視圖子類

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

提供 get、put、patch方法

繼承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

7)RetrieveUpdateDestoryAPIView

提供 get、put、patch、delete方法

繼承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

視圖集ViewSet

使用視圖集ViewSet,能夠將一系列邏輯相關的動做放到一個類中:

  • list() 提供一組數據

  • retrieve() 提供單個數據

  • create() 建立數據

  • update() 保存數據

  • destory() 刪除數據

ViewSet視圖集類再也不實現get()、post()等方法,而是實現動做 action 如 list() 、create() 等。

視圖集只在使用as_view()方法的時候,纔會將action動做與具體請求方式對應上。如:

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)

  在設置路由時,咱們能夠以下操做:

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

經常使用視圖集父類

1)ViewSet

  繼承自APIViewViewSetMixin,做用也與APIView基本相似,提供了身份認證、權限校驗、流量管理等。

  ViewSet主要經過繼承ViewSetMixin來實如今調用as_view()時傳入字典(如{'get':'list'})的映射處理工做。

在ViewSet中,沒有提供任何動做action方法,須要咱們本身實現action方法。

2)GenericViewSet

  使用ViewSet一般並不方便,由於list、retrieve、create、update、destory等方法都須要本身編寫,而這些方法與前面講過的Mixin擴展類提供的方法同名,因此咱們能夠經過繼承Mixin擴展類來複用這些方法而無需本身編寫。可是Mixin擴展類依賴與GenericAPIView,因此還須要繼承GenericAPIView

  GenericViewSet就幫助咱們完成了這樣的繼承工做,繼承自GenericAPIViewViewSetMixin,在實現了調用as_view()時傳入字典(如{'get':'list'})的映射處理工做的同時,還提供了GenericAPIView提供的基礎方法,能夠直接搭配Mixin擴展類使用。

舉例:

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

  url的定義

urlpatterns = [
    path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})),
    re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})),

]

3)ModelViewSet

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

4)ReadOnlyModelViewSet

  繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin。

視圖集中定義附加action動做

  在視圖集中,除了上述默認的方法動做外,還能夠添加自定義動做。

舉例:

from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def login(self,request):
        """學生登陸功能"""
        return Response({"message":"登陸成功"})

  url的定義

urlpatterns = [
    path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
    re_path("students8/(?P<pk>\d+)/",
            views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),

    path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"}))

]

action屬性

  在視圖集中,咱們能夠經過action對象屬性來獲取當前請求視圖集時的action動做是哪一個。

例如:

from rest_framework.viewsets import ModelViewSet
from students.models import Student
from .serializers import StudentModelSerializer
from rest_framework.response import Response
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get_new_5(self,request):
        """獲取最近添加的5個學生信息"""
        # 操做數據庫
        print(self.action) # 獲取本次請求的視圖方法名
        
        
經過路由訪問到當前方法中.能夠看到本次的action就是請求的方法名

路由Routers

對於視圖集ViewSet,咱們除了能夠本身手動指明請求方式與動做action之間的對應關係外,還可使用Routers來幫助咱們快速實現路由信息。

REST framework提供了兩個router

  • SimpleRouter

  • DefaultRouter

使用方法

1) 建立router對象,並註冊視圖集,例如:

from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'router_stu', StudentModelViewSet, base_name='student')

register(prefix, viewset, base_name)

  • prefix 該視圖集的路由前綴

  • viewset 視圖集

  • base_name 路由別名的前綴

如上述代碼會造成的路由以下:

^books/$    name: book-list
^books/{pk}/$   name: book-detail

2)添加路由數據

能夠有兩種方式:

urlpatterns = [
    ...
]
urlpatterns += router.urls

  或

urlpatterns = [
    ...
    url(r'^', include(router.urls))
]

  使用路由類給視圖集生成了路由地址

from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def login(self,request):
        """學生登陸功能"""
        print(self.action)
        return Response({"message":"登陸成功"})

  路由代碼:

from django.urls import path, re_path
from . import views
urlpatterns = [
    ...
]

"""使用drf提供路由類router給視圖集生成路由列表"""
# 實例化路由類
# drf提供一共提供了兩個路由類給咱們使用,他們用法一致,功能幾乎同樣
from rest_framework.routers import DefaultRouter
router = DefaultRouter()

# 註冊視圖集
# router.register("路由前綴",視圖集類)
router.register("router_stu",views.StudentModelViewSet)

# 把生成的路由列表追加到urlpatterns
print( router.urls )
urlpatterns += router.urls

  上面的代碼就成功生成了路由地址[增/刪/改/查一條/查多條的功能],可是不會自動咱們在視圖集自定義方法的路由。

因此咱們若是也要給自定義方法生成路由,則須要進行action動做的聲明。

視圖集中附加action的聲明

在視圖集中,若是想要讓Router自動幫助咱們爲自定義的動做生成路由信息,須要使用rest_framework.decorators.action裝飾器。

以action裝飾器裝飾的方法名會做爲action動做名,與list、retrieve等同。

action裝飾器能夠接收兩個參數:

  • methods: 聲明該action對應的請求方式,列表傳遞

  • detail

    : 聲明該action的路徑是否與單一資源對應,及是不是

xxx/<pk>/action方法名/
    • True 表示路徑格式是xxx/<pk>/action方法名/

    • False 表示路徑格式是xxx/action方法名/

舉例:

from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action

class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    # methods 設置當前方法容許哪些http請求訪問當前視圖方法
    # detail 設置當前視圖方法是不是操做一個數據
    # detail爲True,表示路徑名格式應該爲 router_stu/{pk}/login/
    @action(methods=['get'], detail=True)
    def login(self, request,pk):
        """登陸"""
        ...

    # detail爲False 表示路徑名格式應該爲 router_stu/get_new_5/
    @action(methods=['put'], detail=False)
    def get_new_5(self, request):
        """獲取最新添加的5個學生信息"""
        ...

  由路由器自動爲此視圖集自定義action方法造成的路由會是以下內容:

^router_stu/get_new_5/$    name: router_stu-get_new_5
^router_stu/{pk}/login/$   name: router_stu-login

2.3 路由router造成URL的方式

1) SimpleRouter

 

 

 

2)DefaultRouter

 

 

 

DefaultRouter與SimpleRouter的區別是,DefaultRouter會多附帶一個默認的API根視圖,返回一個包含全部列表視圖的超連接響應數據

相關文章
相關標籤/搜索