drf除了在數據序列化部分簡寫代碼之外,還在視圖中提供了簡寫操做。因此在django原有的django.views.View類基礎上,drf封裝了多個子類出來提供給咱們使用。前端
Django REST framwork 提供的視圖的主要做用:python
控制序列化器的執行(檢驗、保存、轉換數據)數據庫
控制數據庫查詢的執行django
調用請求類和響應類(這兩個類也是由drf幫咱們再次擴展了一些功能類)。json
REST framework 傳入視圖的request對象再也不是Django默認的HttpRequest對象,而是REST framework提供的擴展了HttpRequest類的Request類的對象。後端
REST framework 提供了Parser解析器,在接收到請求後會自動根據Content-Type指明的請求數據類型(如JSON、表單等)將請求數據進行parse解析,解析爲類字典[QueryDict]對象保存到Request對象中。服務器
Request對象的數據是自動根據前端發送數據的格式進行解析以後的結果。app
post
測試
返回解析以後的請求體數據。相似於Django中標準的 request.POST 和 request.FILES 屬性,但提供以下特性:
包含了解析以後的文件和非文件數據
包含了對POST、PUT、PATCH請求方式解析後的數據
利用了REST framework的parsers解析器,不只支持表單類型數據,也支持JSON數據
request.query_params與Django標準的 request.GET 相同,只是更換了更正確的名稱而已。
from rest_framework.response import Response
REST framework提供了一個響應類Response,使用該類構造響應對象時,響應的具體數據內容會被轉換(render渲染)成符合前端需求的類型。
REST framework提供了 Renderer 渲染器,用來根據請求頭中的Accept(接收數據類型聲明)來自動轉換響應數據到對應格式。若是前端請求中未進行Accept聲明,則會採用默認方式處理響應數據,咱們能夠經過配置來修改默認響應格式。
能夠在rest_framework.settings查找全部的drf默認配置項
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( # 默認響應渲染類 'rest_framework.renderers.JSONRenderer', # json渲染器 'rest_framework.renderers.BrowsableAPIRenderer', # 瀏覽API渲染器 ) }
構造方式:
Response(data, status=None, template_name=None, headers=None, content_type=None)
data數據不要是render處理以後的數據,只需傳遞python的內建類型數據便可,REST framework會使用 renderer 渲染器處理data。
data不能是複雜結構的數據,如Django的模型類對象,對於這樣的數據咱們可使用 Serializer 序列化器序列化處理後(轉爲了Python字典類型)再傳遞給data參數。
參數說明:
data: 爲響應準備的序列化處理後的數據;
status: 狀態碼,默認200;
template_name: 模板名稱,若是使用HTMLRenderer 時需指明;
headers: 用於存放響應頭信息的字典;
content_type: 響應數據的Content-Type,一般此參數無需傳遞,REST framework會根據前端所需類型數據來設置該參數。
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
3.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.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
3.4 客戶端錯誤---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
3.5 服務器錯誤---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
REST framework 提供了衆多的通用視圖基類與擴展類,以簡化視圖的編寫。
Django REST framwork 提供的視圖的主要做用:
控制數據庫查詢的執行
下面咱們介紹一下兩個視圖基類
from rest_framework.views import APIView
APIView 是REST framework提供的全部視圖的基類,繼承自Django的View父類。
APIView 與View的不一樣之處在於:
傳入到視圖方法中的是REST framework的request對象,而不是Django的HttpRequest對象;
視圖方法能夠返回REST framework的Response對象
任何APIException異常都會被捕獲到,而且處理成合適的響應信息;
在進行dispatch()分發前,會對請求進行身份認證、權限檢查、流量控制。
支持定義的類屬性
authentication_classes 列表或元祖,身份認證類
permissoin_classes 列表或元祖,權限檢查類
throttle_classes 列表或元祖,流量控制類
在APIView中仍以常規的類視圖定義方法來實現get() 、post() 或者其餘請求方式的方法。
from rest_framework.generics import GenericAPIView
繼承自APIView,主要增長了操做序列化器和數據庫查詢的方法,做用是爲下面Mixin擴展類的執行提供方法支持。一般在使用時,可搭配一個或多個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
返回序列化器對象,主要用來提供給Mixin擴展類使用,若是咱們在視圖中想要獲取序列化器對象,也能夠直接調用此方法。
提供的關於數據庫查詢的屬性與方法
屬性:
queryset 指明使用的數據查詢集
get_queryset(self)
返回視圖使用的查詢集,主要用來提供給Mixin擴展類使用,是列表視圖與詳情視圖獲取數據的基礎,默認返回queryset屬性,能夠重寫,例如:
def get_queryset(self): user = self.request.user return user.accounts.all()
返回詳情視圖所需的模型類數據對象,主要用來提供給Mixin擴展類使用。
在試圖中能夠調用該方法獲取詳情信息的模型類對象。
其餘能夠設置的屬性
pagination_class 指明分頁控制類
filter_backends 指明過濾控制後端
簡單介紹了一下,下面咱們就經過代碼來感覺一下。
首先建立新的應用
python3 manage.py startapp req
下面所用到的序列化器類:
from students.models import Student from rest_framework import serializers class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ["id", "name", "age", "sex"] extra_kwargs = { "name": {"max_length": 10, "min_length": 4}, "age": {"max_value": 150, "min_value": 0}, } def validate_name(self, data): if data == "root": raise serializers.ValidationError("用戶名不能爲root!") return data def validate(self, attrs): name = attrs.get('name') age = attrs.get('age') if name == "alex" and age == 22: raise serializers.ValidationError("alex在22時的故事。。。") return attrs
在req應用下的urls.py文件:
urlpatterns = [ # View與APIView的區別 path("student1/", views.Student1View.as_view()), path("student2/", views.Student2APIView.as_view()), ]
在req應用下的views.py文件:
""" 測試代碼:區分django的 View 和 drf的 APIView """ from django.views import View from django.http import JsonResponse class Student1View(View): def get(self, request): print(request) # 這是django提供的HttpRequest類 print(request.GET) """打印效果: <WSGIRequest: GET '/req/student1/'> """ data_dict = {'name': "alex", "age": 18} return JsonResponse(data_dict) from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status class Student2APIView(APIView): def get(self, request): print(request) # rest_framework擴展後的request print(request.query_params) print(request.data) """打印效果 <rest_framework.request.Request object at 0x00000000054D8898> """ data_dict = {'name': "alex", "age": 18} return Response(data_dict, status=status.HTTP_204_NO_CONTENT, headers={"name": "xiaobai"})
在req應用下的urls.py文件:
urlpatterns = [ # View與APIView的區別 path("student1/", views.Student1View.as_view()), path("student2/", views.Student2APIView.as_view()), # 使用APIView path("student3/", views.Student3APIView.as_view()), re_path(r"^student3/(?P<pk>\d+)/$", views.Student4APIView.as_view()), ]
在req應用下的views.py文件:
""" 使用APIView提供學生信息的5個API接口 GET /req/student3/ # 獲取所有數據 POST /req/student3/ # 添加數據 GET /req/student3/(?P<pk>\d+) # 獲取一條數據 PUT /req/student3/(?P<pk>\d+) # 更新一條數據 DELETE /req/student3/(?P<pk>\d+) # 刪除一條數據 """ from students.models import Student from req.serializers import StudentModelSerializer class Student3APIView(APIView): def get(self, request): """獲取全部數據""" student_list = Student.objects.all() # 序列化操做 serializer = StudentModelSerializer(instance=student_list, many=True) return Response(serializer.data) def post(self, request): # 獲取用戶提交的數據 data_dict = request.data # 實例化序列化器對象 serializer = StudentModelSerializer(data=data_dict) # 數據校驗 serializer.is_valid(raise_exception=True) # 保存數據 serializer.save() return Response(serializer.validated_data) class Student4APIView(APIView): def get(self, request, pk): # 過濾pk對應的學生對象 student_obj = Student.objects.get(pk=pk) serializer = StudentModelSerializer(instance=student_obj) return Response(serializer.data) def put(self, request, pk): # 過濾pk對應的學生對象 student_obj = Student.objects.get(pk=pk) # 獲取用戶提交的數據 data_dict = request.data serializer = StudentModelSerializer(instance=student_obj, data=data_dict) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.validated_data) def delete(self, request, pk): Student.objects.filter(pk=pk).delete() return Response(status=status.HTTP_204_NO_CONTENT)
在req應用下的urls.py文件:
urlpatterns = [ # View與APIView的區別 path("student1/", views.Student1View.as_view()), path("student2/", views.Student2APIView.as_view()), # 使用APIView path("student3/", views.Student3APIView.as_view()), re_path(r"^student3/(?P<pk>\d+)/$", views.Student4APIView.as_view()), # 使用GenericAPIView path("student4/", views.Student5GenericAPIView.as_view()), re_path(r"^student4/(?P<pk>\d+)/$", views.Student6GenericAPIView.as_view()), ]
在req應用下的views.py文件:
""" 使用GenericAPIView提供學生信息的5個API接口 GET /req/student4/ # 獲取所有數據 POST /req/student4/ # 添加數據 GET /req/student4/(?P<pk>\d+) # 獲取一條數據 PUT /req/student4/(?P<pk>\d+) # 更新一條數據 DELETE /req/student4/(?P<pk>\d+) # 刪除一條數據 """ from rest_framework.generics import GenericAPIView class Student5GenericAPIView(GenericAPIView): # 當前視圖類中操做的公共數據,先從數據庫查詢出來 queryset = Student.objects.all() # 設置類視圖中全部方法共有調用的序列化器類 serializer_class = StudentModelSerializer def get(self, request): # 獲取模型數據 student_list = self.get_queryset() # 調用序列化器 serializer = self.get_serializer(instance=student_list, many=True) return Response(serializer.data) def post(self, request): """新增數據""" # 獲取用戶提交的數據並實例化序列化器對象 serializer = self.get_serializer(data=request.data) # 數據校驗 serializer.is_valid(raise_exception=True) # 保存數據 serializer.save() return Response(serializer.data) class Student6GenericAPIView(GenericAPIView): # 當前視圖類中操做的公共數據,先從數據庫查詢出來 queryset = Student.objects.all() # 設置類視圖中全部方法共有調用的序列化器類 serializer_class = StudentModelSerializer def get(self, request, pk): """參數pk名,必需要叫pk,不然會報錯。""" # 獲取模型對象 instance = self.get_object() serializer = self.get_serializer(instance=instance) return Response(serializer.data) def put(self, request, pk): instance = self.get_object() serializer = self.get_serializer(instance=instance, data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data) def delete(self, request, pk): # 獲取模型對象 instance = self.get_object() # 刪除模型對象 instance.delete() return Response(status=status.HTTP_204_NO_CONTENT)
""" 使用GenericAPIView結合視圖Mixin擴展類,快速實現數據接口的APIView ListModelMixin 實現查詢全部數據功能 CreateModelMixin 實現添加數據的功能 RetrieveModelMixin 實現查詢一條數據功能 UpdateModelMixin 更新一條數據的功能 DestroyModelMixin 刪除一條數據的功能 """
在req應用下的urls.py文件:
urlpatterns = [ # View與APIView的區別 path("student1/", views.Student1View.as_view()), path("student2/", views.Student2APIView.as_view()), # 使用APIView path("student3/", views.Student3APIView.as_view()), re_path(r"^student3/(?P<pk>\d+)/$", views.Student4APIView.as_view()), # 使用GenericAPIView path("student4/", views.Student5GenericAPIView.as_view()), re_path(r"^student4/(?P<pk>\d+)/$", views.Student6GenericAPIView.as_view()), # 使用GenericAPIView,結合Mixin的擴展類 path("student5/", views.Student7GenericAPIView.as_view()), re_path(r"^student5/(?P<pk>\d+)/$", views.Student8GenericAPIView.as_view()), ]
在req應用下的views.py文件:
from rest_framework.mixins import ListModelMixin, CreateModelMixin class Student7GenericAPIView(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 Student8GenericAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get(self, request, pk): return self.retrieve(request) def put(self, request, pk): return self.update(request) def delete(self, request, pk): return self.destroy(request)
在req應用下的urls.py文件:
urlpatterns = [ # View與APIView的區別 path("student1/", views.Student1View.as_view()), path("student2/", views.Student2APIView.as_view()), # 使用APIView path("student3/", views.Student3APIView.as_view()), re_path(r"^student3/(?P<pk>\d+)/$", views.Student4APIView.as_view()), # 使用GenericAPIView path("student4/", views.Student5GenericAPIView.as_view()), re_path(r"^student4/(?P<pk>\d+)/$", views.Student6GenericAPIView.as_view()), # 使用GenericAPIView,結合Mixin的擴展類 path("student5/", views.Student7GenericAPIView.as_view()), re_path(r"^student5/(?P<pk>\d+)/$", views.Student8GenericAPIView.as_view()), # 使用內置的擴展子類,生成API接口 path("student6/", views.Student9GenericAPIView.as_view()), re_path(r"^student6/(?P<pk>\d+)/$", views.Student10GenericAPIView.as_view()), ]
在req應用下的views.py文件:
""" DRF裏面,內置了一些同時繼承了GenericAPIView和Mixins擴展類的視圖子類, 咱們能夠直接繼承這些子類就能夠生成對應的API接口 """ """ ListAPIView 獲取全部數據 CreateAPIView 添加數據 """ from rest_framework.generics import ListAPIView, CreateAPIView class Student9GenericAPIView(ListAPIView, CreateAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer """ RetrieveAPIView 獲取一條數據 UpdateAPIView 更新一條數據 DestorAPIView 刪除一條數據 RetrieveUpdateDestoryAPIView 上面三個的縮寫 """ from rest_framework.generics import RetrieveUpdateDestroyAPIView class Student10GenericAPIView(RetrieveUpdateDestroyAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer
在req應用下的urls.py文件:
urlpatterns = [ # View與APIView的區別 path("student1/", views.Student1View.as_view()), path("student2/", views.Student2APIView.as_view()), # 使用APIView path("student3/", views.Student3APIView.as_view()), re_path(r"^student3/(?P<pk>\d+)/$", views.Student4APIView.as_view()), # 使用GenericAPIView path("student4/", views.Student5GenericAPIView.as_view()), re_path(r"^student4/(?P<pk>\d+)/$", views.Student6GenericAPIView.as_view()), # 使用GenericAPIView,結合Mixin的擴展類 path("student5/", views.Student7GenericAPIView.as_view()), re_path(r"^student5/(?P<pk>\d+)/$", views.Student8GenericAPIView.as_view()), # 使用內置的擴展子類,生成API接口 path("student6/", views.Student9GenericAPIView.as_view()), re_path(r"^student6/(?P<pk>\d+)/$", views.Student10GenericAPIView.as_view()), # 視圖集 path("student7/", views.Student11GenericAPIView.as_view({"get": "list", "post": "create"})), re_path(r"^student7/(?P<pk>\d+)/$", views.Student11GenericAPIView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), ]
在req應用下的views.py文件:
""" 視圖集 上面5個接口使用了8行代碼生成,可是咱們能夠發現有一半的代碼重複了 因此,咱們要把這些重複的代碼進行整合,可是依靠原來的類視圖,其實有2方面產生衝突的 1. 查詢全部數據、添加數據是不須要聲明pk的,而其餘的接口須要 [路由衝突了] 2. 查詢全部數據和查詢一條數據,都是屬於get請求 [請求方法衝突了] 爲了解決上面的2個問題,因此DRF提供了視圖集來解決這個問題 """ from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin # 這兩個是等價的 # class Student11GenericAPIView(GenericViewSet, ListModelMixin, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin): class Student11GenericAPIView(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer