視圖前端
2個視圖基類python
APIView數據庫
GenericAPIViewdjango
5個試圖擴展類後端
5)DestoryModelMixinfetch
7)RetrieveUpdateDestoryAPIView
Django REST framwork 提供的視圖的主要做用:
控制序列化器的執行(檢驗、保存、轉換數據)
控制數據庫查詢的執行【數據庫的刪除/查詢代碼寫在視圖中,更新和添加寫在序列化器】
REST framework 提供了衆多的通用視圖基類與擴展類,以簡化視圖的編寫。
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)
通用視圖類主要做用就是把視圖中的獨特的代碼抽取出來,讓視圖方法中的代碼更加通用,方便把通用代碼進行簡寫。
rest_framework.generics.GenericAPIView
繼承自APIView,主要增長了操做序列化器和數據庫查詢的類屬性,做用是爲下面的Minxin視圖擴展類的執行提供方法支持。一般在經常使用時,可搭配一個或多個Mixin擴展類。
提供的關於序列化器使用的屬性與方法:
屬性:
serializer_class 指明視圖使用的序列化器類。
方法:
get_serializer_class(self)
返回序列化器類,默認返回serializer_class
,能夠重寫,例如:
def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer
get_serializer(self,args,*kwargs)
返回序列化器對象,主要用來提供給Mixin擴展類使用,若是咱們在視圖中想要獲取序列化器對象,也能夠直接調用此方法。
view 當前請求的類視圖對象
format 當前請求指望返回的數據格式
queryset 指明使用的數據查詢集
方法:
get_queryset(self)
返回視圖使用的查詢集,主要用來提供給Mixin擴展類使用,是列表視圖與詳情視圖獲取數據的基礎,默認返回queryset
屬性,能夠重寫,例如:
def get_queryset(self): user = self.request.user return user.accounts.all()
在試圖中能夠調用該方法獲取詳情信息的模型類對象。
若詳情訪問的模型類對象不存在,會返回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")
提供了幾種後端視圖(對數據資源進行曾刪改查)處理流程的實現,若是須要編寫的視圖屬於這五種,則視圖能夠經過繼承相應的擴展類來複用代碼,減小本身編寫的代碼量。
這五個擴展類須要搭配GenericAPIView父類,由於五個擴展類的實現須要調用GenericAPIView提供的序列化器與數據庫查詢的方法。
該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)
若是序列化器對前端發送的數據驗證失敗,返回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 {}
若是存在,返回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)
同時也提供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)
成功返回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、CreateModelMixin
繼承自:GenericAPIView、ListModelMixin
繼承自: GenericAPIView、RetrieveModelMixin
繼承自:GenericAPIView、DestoryModelMixin
繼承自:GenericAPIView、UpdateModelMixin
繼承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
繼承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
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'}) ]
ViewSet主要經過繼承ViewSetMixin來實如今調用as_view()時傳入字典(如{'get':'list'})的映射處理工做。
在ViewSet中,沒有提供任何動做action方法,須要咱們本身實現action方法。
GenericViewSet就幫助咱們完成了這樣的繼承工做,繼承自GenericAPIView
與ViewSetMixin
,在實現了調用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"})), ]
舉例:
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"})) ]
例如:
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就是請求的方法名
REST framework提供了兩個router
SimpleRouter
1) 建立router對象,並註冊視圖集,例如:
from rest_framework import routers router = routers.DefaultRouter() router.register(r'router_stu', StudentModelViewSet, base_name='student')
prefix 該視圖集的路由前綴
viewset 視圖集
base_name 路由別名的前綴
如上述代碼會造成的路由以下:
^books/$ name: book-list ^books/{pk}/$ name: book-detail
能夠有兩種方式:
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裝飾器裝飾的方法名會做爲action動做名,與list、retrieve等同。
action裝飾器能夠接收兩個參數:
methods: 聲明該action對應的請求方式,列表傳遞
detail
: 聲明該action的路徑是否與單一資源對應,及是不是
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)DefaultRouter
DefaultRouter與SimpleRouter的區別是,DefaultRouter會多附帶一個默認的API根視圖,返回一個包含全部列表視圖的超連接響應數據