Rest_Framework由淺入深:從CBV到ModelViewSet源碼一步步解析
1、Django Rest_Framework介紹
Django REST framework是一個建立在Django基礎(chǔ)之上的Web應(yīng)用開發(fā)框架,可以快速的開發(fā)REST API接口應(yīng)用。在REST framework中,提供了序列化器Serialzier的定義,可以幫助我們簡化序列化與反序列化的過程,不僅如此,還提供豐富的類視圖、擴展類、視圖集來簡化視圖的編寫工作。REST framework還提供了認證、權(quán)限、限流、過濾、分頁、接口文檔等功能支持。REST framework提供了一個API 的Web可視化界面來方便查看測試接口。
2、特點
a、提供了定義序列化器Serializer的方法,可以快速根據(jù) Django ORM或者其它庫自動序列化、反序列化;
b、提供了豐富的類視圖、Mixin擴展類,簡化視圖的編寫,豐富的定制層級:函數(shù)視圖、類視圖、視圖集合到自動生成 API;
c、滿足各種需要多種身份認證和權(quán)限認證方式的支持內(nèi)置了限流系統(tǒng)直觀的 API web 界面,可以方便我們調(diào)試開發(fā)api接口,可擴展性強,插件豐富。
一、Django的CBV
1、執(zhí)行順序:
先從路由的as_view() 開始,
執(zhí)行BookView類繼承的View類里的as_view() 里的view(),
view() 的返回值是View類的dispatch(),
dispatch() 進行分發(fā)執(zhí)行get、post、put等方法。
views.py
# author xsy
from django.views import View
class BookView(View):
def get(self,request):
return HttpResponse('get')
def post(self,request):
return HttpResponse('post')
urls.py
# author xsy
from django.urls import path
from .views import *
urlpatterns = [
path('book/', BookView.as_view()),
]
View類的大概邏輯
# author xsy
class View():
def as_view(cls, **initkwargs):
def view(self):
return self.dispatch()
return view
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr( self, request.method.lower(), self.http_method_not_allowed )
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
二、DRF的APIView
1、相比原生django的優(yōu)勢:
a、django原生的request.POST存在只會解析uriencoded 不會解析json的問題;
b、APIView類的dispatch方法解決該問題,而且還會對請求的客戶端進行身份認證、權(quán)限檢查、流量控制。
2、執(zhí)行順序:
先從路由的as_view() 開始,
執(zhí)行BookView類繼承的APIView類里的as_view(),
而該as_view() 在內(nèi)部重寫了APIView類的父類View的as_view() 方法,
所以執(zhí)行的是父類View的as_view(),
而View的as_view()方法在內(nèi)部的返回值是dispatch()
該dispatch()是先從APIView類里查找,
因為APIView類有dispatch(),
所以最終執(zhí)行的是APIView類的dispatch() 進行分發(fā)。
views.py
# author xsy
from rest_framework.views import APIView
class BookView(APIView):
def get(self,request):
return HttpResponse('get')
def post(self,request):
return HttpResponse('post')
APIView類的大概邏輯
# author xsy
# APIView的父類View的邏輯
class View():
def as_view(cls, **initkwargs):
def view(self):
return self.dispatch()
return view
def dispatch(self, request, *args, **kwargs):
if request.method.lower() in self.http_method_names:
handler = getattr( self, request.method.lower(), self.http_method_not_allowed )
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
class APIView(View):
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
return csrf_exempt(view)
def dispatch(self, request, *args, **kwargs):
# 構(gòu)建新的request對象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
# 初始化:認證、權(quán)限、限流組件三件套
if request.method.lower() in self.http_method_names:
handler = getattr( self, request.method.lower(), self.http_method_not_allowed )
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
三、序列化器
1、使用Serializer和APIView
Serializer進行序列化和反序列化
數(shù)據(jù)庫的數(shù)據(jù)到前端進行序列化
前端的數(shù)據(jù)上傳到數(shù)據(jù)庫進行反序列化
a、**serializer.save()**的邏輯:
如果self.instance is not None執(zhí)行update()
否則執(zhí)行create() 分別對應(yīng)put()和post()
但BaseSerializer類里的create()和update()必須重寫
所以Bookserializers類里有這兩個方法
b、serializer.data
BookView類get()返回的serializer.data,是Serializer類data()
該方法重寫了Serializer類的父類BaseSerializer類的data()方法
model.py
# author xsy
from django.db import models
# Create your models here.
class Books(models.Model):
title = models.CharField(max_length=32,verbose_name="書籍名稱")
price = models.IntegerField(verbose_name="價格")
serializers.py
# author xsy
from rest_framework import serializers
from .models import *
class Bookserializers(serializers.Serializer):
title = serializers.CharField(max_length=16)
price = serializers.IntegerField()
# 使用下面這種可以修改名稱
# jiaqian = serializers.IntegerField(source='price')
def create(self, validated_data):
newbook = Books.objects.create(**self.validated_data)
return newbook
def update(self, instance, validated_data):
Books.objects.filter(pk=instance.pk).update(**self.validated_data)
update_book = Books.objects.get(pk=instance.pk)
return update_book
views.py
# author xsy
from rest_framework.views import APIView
# 不使用djangO自帶的HttpResponse 而是用rest_framework的Response可以將返回值變成json
from rest_framework.response import Response
from .models import *
from .serializers import *
class BookView(APIView):
def get(self,request):
books = Books.objects.all()
serializer = Bookserializers(instance=books,many=True)
return Response(serializer.data)
def post(self,request):
serializer = Bookserializers(data=request.data)
if serializer.is_valid():
# Books.objects.create(**serializer.validated_data)
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
class BookDetailView(APIView):
def get(self,request,id):
book = Books.objects.get(pk=id)
serializer = Bookserializers(instance=book,many=False)
return Response(serializer.data)
def put(self,request,id):
serializer = Bookserializers(instance=Books.objects.get(pk=id),data=request.data)
if serializer.is_valid():
# Books.objects.filter(pk=id).update(**serializer.validated_data)
# serializer.instance = Books.objects.get(pk=id)
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
def delete(self,request,id):
Books.objects.get(pk=id).delete()
return Response()
urls.py
# author xsy
from django.urls import path,re_path
from .views import *
urlpatterns = [
path('books/', BookView.as_view()),
re_path('book/(\d+)', BookDetailView.as_view()),
]
2、ModelSerializer和GenericAPIView
a、ModelSerializer相比Serializer
已經(jīng)將模型的字段在內(nèi)部進行封裝;
在內(nèi)部已經(jīng)重寫create()和update();
b、GenericAPIView相當于進一步封裝APIView
1、GenericAPIView繼承APIView類,self.get_serializer_class()等于Bookserializers
2、而self.get_serializer等于self.get_serializer_class()
3、self.get_queryset() 等于取出多條數(shù)據(jù)
4、self.get_object() 等于取出一條數(shù)據(jù)
model.py
# author xsy
from django.db import models
# Create your models here.
class Books(models.Model):
title = models.CharField(max_length=32,verbose_name="書籍名稱")
price = models.IntegerField(verbose_name="價格")
serializers.py
# author xsy
class Bookserializers(serializers.ModelSerializer):
class Meta:
model = Books
# fields = '__all__'
fields = ['title','price']
views.py
# author xsy
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
class BookView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = Bookserializers
def get(self, request):
books = Books.objects.all()
# serializer = Bookserializers(instance=self.get_queryset(),many=True)
# self.get_serializer_class()等于Bookserializers
# self.get_serializer_class()(instance=self.get_queryset(),many=True)
serializer = self.get_serializer(instance=self.get_queryset(),many=True)
return Response(serializer.data)
def post(self,request):
# serializer = Bookserializers(data=request.data)
# serializer = self.get_serializer_class()(data=request.data)
# 三行作用相同
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
# Books.objects.create(**serializer.validated_data)
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
class BookDetailView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = Bookserializers
def get(self,request,pk):
# book = Books.objects.get(pk=id)
# serializer = Bookserializers(instance=book,many=False)
serializer = self.get_serializer(instance=self.get_object(),many=False)
return Response(serializer.data)
def put(self,request,pk):
# serializer = Bookserializers(instance=Books.objects.get(pk=id),data=request.data)
serializer = self.get_serializer(instance=self.get_object(),data=request.data)
if serializer.is_valid():
# Books.objects.filter(pk=id).update(**serializer.validated_data)
# serializer.instance = Books.objects.get(pk=id)
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
def delete(self,request,pk):
# Books.objects.get(pk=id).delete()
self.get_object().delete()
return Response()
四、視圖
1、mixins
ListModelMixin的list方法對應(yīng)BookView的get方法
CreateModelMixin的create方法對應(yīng)BookView的post方法
RetrieveModelMixin的retrieve方法對應(yīng)BookDetailView的get方法
UpdateModelMixin的update方法對應(yīng)BookDetailView的put方法
DestroyModelMixin的destroy方法對應(yīng)BookDetailView的delete方法
views.py
# author xsy
# # #################### mixins ################################
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
class BookView(ListModelMixin,CreateModelMixin,GenericAPIView):
queryset = Books.objects.all()
serializer_class = Bookserializers
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class BookDetailView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
queryset = Books.objects.all()
serializer_class = Bookserializers
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)
2、mixins再封裝版
ListCreateAPIView類將list方法封裝到get方法里,將create方法封裝到post方法里
RetrieveUpdateDestroyAPIView類將retrieve封裝到get方法里,將update方法封裝到put方法里,將destroy方法封裝到delete方法里
views.py
# author xsy
# # #################### mixins再封裝 #########################################
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
class BookView(ListCreateAPIView):
queryset = Books.objects.all()
serializer_class = Bookserializers
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Books.objects.all()
serializer_class = Bookserializers
五、視圖的再次精簡化:GenericViewSet和ModelViewSet
1、GenericViewSet
BookView類繼承六個類,其中GenericViewSet類繼承的ViewSetMixin類實現(xiàn)了將路由傳的字典映射到對應(yīng)的方法,這樣才可以將BookView和BookDetailView和成一個類,而繼承的其他五個類對應(yīng)了增刪改查方法
views.py
# author xsy
# #################### 四、GenericViewSet #########################################
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin
class BookView(GenericViewSet,ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin):
queryset = Books.objects.all()
serializer_class = Bookserializers
urls.py
# author xsy
urlpatterns = [
# GenericViewSet
path('books/', BookView.as_view({'get':'list','post':'create'})),
re_path('book/(?P<pk>\d+)', BookView.as_view({'get':'retrieve','delete':'destroy','put':'update'})),
]
2、ModelViewSet
ModelViewSet類繼承了CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin,ListModelMixin,
GenericViewSet這六個類
views.py文章來源:http://www.zghlxwxcb.cn/news/detail-464343.html
# author xsy
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = Books.objects.all()
serializer_class = Bookserializers
urls.py文章來源地址http://www.zghlxwxcb.cn/news/detail-464343.html
# author xsy
from rest_framework import routers
router = routers.DefaultRouter()
router.register('book',BookView)
urlpatterns = [
]
urlpatterns += router.urls
到了這里,關(guān)于Rest_Framework由淺入深:從CBV到ModelViewSet源碼一步步解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!