寫在前面-->視圖回顧:
Django視圖的使用
-
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>
-
Django的類視圖:
敲黑板: 這里 我們 第一次見到了 View
要明確的是:
- 類視圖View 還是 使用的 Django的 原生 Request 和 Response, 所以 不好用
- 類視圖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ū)別:
Request
對象 不一樣
Response
對象 不一樣任何
APIException
異常都會被捕獲到,并且處理成合適的響應(yīng)信息扰她;在進行
dispatch()分發(fā)前
兽掰,會對請求進行身份認(rèn)證、權(quán)限檢查徒役、流量控制孽尽。繼承了 View 的 get(), post(), put() , delete() 函數(shù)方法
-
關(guān)于
Request
對象其將解析為
類字典對象
保存到Request對象中獲取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
相同 -
關(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
的烁,
- 增加了對于列表視圖和詳情視圖可能用到的通用支持方法。
- 搭配一個或多個Mixin擴展類诈闺。
- 需要實現(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相同
-
lookup_field查詢單一數(shù)據(jù)庫對象時使用的條件字段撮躁,默認(rèn)為'
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類視圖
- Mixin類 定義了一些 方法,
- 通過使用 GenericAPIView 提供的方法霍弹、屬性,
- 實現(xiàn) 列表和詳情頁的 快速實現(xiàn)
-
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()方法
-
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()方法
-
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()方法
-
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)
-
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
ViewSet
類只是一種基于類的View蚪腋,繼承自APIView
它不提供任何方法處理程序(如
get()
orpost()
),而是提供諸如
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')
- 添加路由數(shù)據(jù)
urlpatterns = [
...
]
urlpatterns += router.urls
# 或
urlpatterns = [
...
url(r'^', include(router.urls))
]