在完成序列化器serializers的配置過(guò)后放接,我們可以進(jìn)一步使用DjangoRest framework提供的強(qiáng)大視圖類(lèi)API簡(jiǎn)化視圖的開(kāi)發(fā)呼盆。
Request和Response
(一)Request
首先需要清楚的一點(diǎn)是柠衅,當(dāng)視圖函數(shù)繼承與DRF的View時(shí)成翩,傳入視圖內(nèi)的request對(duì)象就不再是Django默認(rèn)的HttpRequest對(duì)象了败去,而變成了DRF擴(kuò)展的Request類(lèi)對(duì)象暴构,該對(duì)象提供了更友好的數(shù)據(jù)接收方式:
1. request.data
request.data
返回解析之后的請(qǐng)求體數(shù)據(jù),無(wú)需再使用data = json.loads(request.body.decode())
的方法來(lái)獲取post及put等方法傳輸?shù)臄?shù)據(jù)置鼻。
- 包含了解析之后的文件和非文件數(shù)據(jù)
- 包含了對(duì)POST镇饮、PUT、PATCH請(qǐng)求方式解析后的數(shù)據(jù)
- 利用了REST framework的parsers解析器箕母,不僅支持表單類(lèi)型數(shù)據(jù)储藐,也支持JSON數(shù)據(jù)
2. request.query_params
使用request.query_params
獲取前端請(qǐng)求中傳遞的關(guān)鍵字參數(shù),與Django中的request.GET相同嘶是,但DRF的方法命名能更準(zhǔn)確的指明我們?cè)谧鍪裁础?/p>
(二) Response
與Django自帶的HttpResponse對(duì)象不同钙勃,DRF還提供了一個(gè)更為便捷的響應(yīng)類(lèi)
Response:rest_framework.response.Response
。
使用該類(lèi)構(gòu)件響應(yīng)對(duì)象時(shí)聂喇,不必再像之前那樣需先將數(shù)據(jù)進(jìn)行轉(zhuǎn)換辖源。
data數(shù)據(jù)不要是render處理之后的數(shù)據(jù),只需傳遞python的內(nèi)建類(lèi)型數(shù)據(jù)即可希太,REST framework會(huì)使用renderer渲染器處理data克饶。
- 響應(yīng)方式
Response(data, status=None, template_name=None, headers=None, content_type=None)
- 參數(shù)說(shuō)明
參數(shù) | 說(shuō)明 |
---|---|
data | 傳遞的序列化處理后的數(shù)據(jù) |
status | 狀態(tài)碼,默認(rèn)為200 |
template_name | 模板名稱(chēng)誊辉,使用HTMLRenderer 時(shí)需指明 |
headers | 用于存放響應(yīng)頭信息的字典 |
content_type | 響應(yīng)數(shù)據(jù)的Content-Type矾湃,通常此參數(shù)無(wú)需傳遞,REST framework會(huì)根據(jù)前端所需類(lèi)型數(shù)據(jù)來(lái)設(shè)置該參數(shù)堕澄。 |
- 關(guān)于狀態(tài)碼
DRF提供了狀態(tài)碼常量邀跃,導(dǎo)入rest_framework.status
后使用,使用內(nèi)置狀態(tài)碼更加規(guī)范蛙紫。
DRF提供的視圖View類(lèi)
使用DRF提供的視圖類(lèi)時(shí)拍屑,我們不再繼承django自帶的django.views.View
類(lèi),而是繼承來(lái)自DRF的VIEW
一. APIView
APIView是REST framework提供的所有視圖的基類(lèi)惊来,繼承自Django的View父類(lèi):rest_framework.views.APIView
丽涩。
- APIView與View的不同之處在于:
- 傳入到視圖方法中的是REST framework的Request對(duì)象棺滞,而不是Django的HttpRequeset對(duì)象裁蚁;
- 視圖方法可以返回REST framework的Response對(duì)象,視圖會(huì)為響應(yīng)數(shù)據(jù)設(shè)置(render)符合前端要求的格式继准;
- 任何APIException異常都會(huì)被捕獲到枉证,并且處理成合適的響應(yīng)信息;
- 在進(jìn)行dispatch()分發(fā)前移必,會(huì)對(duì)請(qǐng)求進(jìn)行身份認(rèn)證室谚、權(quán)限檢查、流量控制。
- 繼承APIView的視圖類(lèi)代碼示例
from . models import BookInfo
from .serializers import BookModelSerializer # 導(dǎo)入序列化器
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class BooksAPIView(APIView):
# 獲取所有書(shū)
def get(self,request):
books = BookInfo.objects.all()
serializer = BookModelSerializer(books, many=True)
print(serializer.data)
return Response(serializer.data)
# 新增一本書(shū)
def post(self, request):
data_dict = request.data
serializer = BookModelSerializer(data=data_dict)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
二达箍、GenericAPIView
此類(lèi)擴(kuò)展了REST框架的APIView類(lèi):rest_framework.generics.GenericAPIView
娇跟。
增加了對(duì)于列表視圖和詳情視圖可能用到的通用支持方法,通常使用時(shí)仅仆,可搭配一個(gè)或多個(gè)Mixin擴(kuò)展類(lèi)。
基本設(shè)置
使用繼承于GenericAPIView的視圖類(lèi)時(shí)陈瘦,需要先定義基本類(lèi)屬性:
(1)queryset
:列表視圖的查詢集
(2)serializer_class
:視圖使用的序列化器
以上兩個(gè)為必須設(shè)置的屬性
(3)lookup_field
:用于執(zhí)行單個(gè)模型實(shí)例的對(duì)象查找的模型字段,不設(shè)置時(shí)默認(rèn)為pk
字段
(4)lookup_url_kwarg
:查詢單一數(shù)據(jù)時(shí)URL中的參數(shù)關(guān)鍵字名稱(chēng)潮售,默認(rèn)與look_field相同
(5)pagination_class
:分頁(yè)控制類(lèi)
(6)filter_backends
:用于過(guò)濾查詢集的過(guò)濾器后端類(lèi)列表基本方法
(1)get_queryset(self)
: 返回視圖使用的查詢集
(2)get_serializer_class(self)
: 返回序列化器類(lèi)
(3)get_object(self)
: 返回lookup_field
設(shè)置指定的模型類(lèi)數(shù)據(jù)對(duì)象痊项。
3.繼承GenericAPIView視圖類(lèi)的代碼示例
from . models import BookInfo
from .serializers import BookModelSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
class BooksAPIView(GenericAPIView):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
# 獲取所有
def get(self,request):
books = self.get_queryset()
serializer = self.get_serializer(books, many=True)
return Response(serializer.data)
# 新增一本書(shū)
def post(self, request):
data_dict = request.data
serializer = self.get_serializer(data_dict)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
看起來(lái)代碼量并沒(méi)有減少,只是將序列化器的初始化酥诽、數(shù)據(jù)集的查詢提取了出來(lái)鞍泉。
但GenericAPIView類(lèi)主要是聯(lián)合它的Mixin類(lèi)一起使用的。
三肮帐、Mixin擴(kuò)展類(lèi)
from rest_framework.mixins import CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin
DRF總共提供了5個(gè)Mixin擴(kuò)展類(lèi)咖驮,他們只提供操作的方法,而需要同時(shí)繼承GenericAPIView類(lèi)训枢,并繼承對(duì)用功能的Mixin類(lèi):
Minx類(lèi) | 作用 | 調(diào)用方式 |
---|---|---|
ListModelMixin | 實(shí)現(xiàn)查詢集功能(get) | list |
CreateModelMixin | 實(shí)現(xiàn)創(chuàng)建和保存功能(post) | create |
RetrieveModelMixin | 實(shí)現(xiàn)查詢指定單一數(shù)據(jù)功能(get) | retrieve |
UpdateModelMixin | 實(shí)現(xiàn)更新功能(put) | update |
DestroyModelMixin | 實(shí)現(xiàn)刪除功能(delete) | destroy |
- 使用代碼示例
該視圖類(lèi)需要實(shí)現(xiàn)查詢所有書(shū)功能游沿、創(chuàng)建一本新書(shū)的功能,因此除繼承GenericAPIView外, 還需繼承ListModelMixin, CreateModelMixin類(lèi)肮砾。
from . models import BookInfo
from .serializers import BookModelSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin
class BooksAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
# 獲取所有
def get(self,request):
return self.list(request)
# 新增一本書(shū)
def post(self, request):
return self.create(request)
class BookAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
# 獲取指定id書(shū)
def get(self,request, pk):
return self.retrieve(request, pk)
# 修改指定書(shū)信息
def put(self, request, pk):
return self.update(request, pk)
# 刪除指定書(shū)
def delete(self,request, pk):
return self.delete(request,pk)
可以看到诀黍,使用Mixin擴(kuò)展類(lèi)后,代碼量大大縮減仗处,連邏輯代碼都被封裝起來(lái)了眯勾。
- mixin源碼示例
mixin類(lèi)在內(nèi)部定義了方法將:數(shù)據(jù)集的查詢及獲取、頁(yè)碼操作婆誓、序列化器的調(diào)用吃环、Response響應(yīng) 都封裝在了一起,我們需要做的就只是繼承然后調(diào)用該內(nèi)部方法即可ListModelMixin源碼示例:
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)
其內(nèi)部相當(dāng)于將我們寫(xiě)的邏輯代碼部分都封裝起來(lái)了洋幻,因?yàn)槠溥壿嬃鞒潭际窍嗤挠羟帷ixin類(lèi)提供.list()和.create()等操作,然后我們將這些get和post方法明確地綁定到適當(dāng)?shù)牟僮魃衔牧簟J惯@種類(lèi)型的代碼極大減少好唯。
四、基于GenericAPIView和Mixin擴(kuò)展類(lèi)的子類(lèi)
到目前為止燥翅,使用Mixin的擴(kuò)展類(lèi)已經(jīng)讓我們的代碼量足夠簡(jiǎn)潔了骑篙,但Rest framework還進(jìn)行了進(jìn)一步的封裝,在符合條件的情況下可以連定義get森书、post等方法及return的語(yǔ)句也不用再我們自己寫(xiě)靶端。
- 可用子類(lèi)試圖介紹
一共內(nèi)置了9個(gè)可用子類(lèi)試圖
子類(lèi)視圖類(lèi) | 作用 | 對(duì)應(yīng)方法 |
---|---|---|
CreateAPIView | 新建 | post |
ListAPIView | 查詢所有 | get |
RetireveAPIView | 查詢指定 | get |
DestoryAPIView | 刪除指定 | delete |
UpdateAPIView | 更新指定 | put |
ListCreateAPIView | 查詢所有及創(chuàng)建 | post谎势、get |
RetrieveUpdateAPIView | 查詢指定及更新 | get、put |
RetrieveDestoryAPIView | 查詢指定及刪除 | get杨名、delete |
RetrieveUpdateDestoryAPIView | 查詢指定脏榆、更新、刪除 | get台谍、put姐霍、delete |
- 使用代碼示例
只需要不過(guò)10行代碼,就可以實(shí)現(xiàn)最初基于Django的View類(lèi)時(shí)需要寫(xiě)的100多行代碼效果典唇。
需要我們自己實(shí)現(xiàn)的只有數(shù)據(jù)集的定義及序列化器的定義镊折,其余都基于序列化器進(jìn)行了封裝完成。
from . models import BookInfo
from .serializers import BookModelSerializer
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
class BooksAPIView(ListCreateAPIView):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
class BookAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
3.源碼示例
其實(shí)源碼內(nèi)就是封裝了對(duì)方法的定義及return
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for retrieving, updating or deleting a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
總結(jié)
我用自己的話總結(jié)了這些不同的類(lèi)到底實(shí)現(xiàn)了什么功能介衔,可能有欠妥的地方恨胚,歡迎提出。
Serializer:構(gòu)建序列化器炎咖,視圖函數(shù)內(nèi)不再需要自己構(gòu)造鍵值對(duì)數(shù)據(jù)格式赃泡。
Response:DRF提供的Response對(duì)象返回?cái)?shù)據(jù)時(shí),不需要再次轉(zhuǎn)換數(shù)據(jù)格式乘盼,只需將request升熊。data傳遞給它即可,它能完成自動(dòng)處理绸栅。
APIView:基本DRF視圖類(lèi)级野,提供了新的Request類(lèi)。使用request.data可直接接收轉(zhuǎn)換后的數(shù)據(jù)粹胯。
GenericAPIView:基于APIView蓖柔,從視圖函數(shù)中提取出了序列化器和查詢集,主要用于配合Mixin類(lèi)使用风纠。
Mixin擴(kuò)展類(lèi)ListModelMixin等:基于object况鸣,視圖類(lèi)使用時(shí)需要同時(shí)繼承Mixin類(lèi)和Generic類(lèi)。此處實(shí)現(xiàn)了邏輯代碼封裝竹观,將數(shù)據(jù)接收镐捧、查詢、驗(yàn)證臭增、響應(yīng)都封裝在了list懂酱、create、retrive速址、update玩焰、destroy方法里面由驹,只需再調(diào)用這些封裝好的方法即可芍锚。
擴(kuò)展類(lèi)子類(lèi)CreateAPIView等:將方法的定義和return返回都封裝了昔园,我們?cè)谝晥D類(lèi)中需要做的只剩指定序列化器與查詢集,其繼承類(lèi)將完成剩下的所有并炮。