1、Django Rest_Framework介绍
Django REST framework是一个建立在Django基础之上的Web应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
2、特点
a、提供了定义序列化器Serializer的方法,可以快速根据 Django ORM或者其它库自动序列化、反序列化;
b、提供了丰富的类视图、Mixin扩展类,简化视图的编写,丰富的定制层级:函数视图、类视图、视图集合到自动生成 API;
c、满足各种需要多种身份认证和权限认证方式的支持内置了限流系统直观的 API web 界面,可以方便我们调试开发api接口,可扩展性强,插件丰富。
先从路由的as_view() 开始,
执行BookView类继承的View类里的as_view() 里的view(),
view() 的返回值是View类的dispatch(),
dispatch() 进行分发执行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)
a、django原生的request.POST存在只会解析uriencoded 不会解析json的问题;
b、APIView类的dispatch方法解决该问题,而且还会对请求的客户端进行身份认证、权限检查、流量控制。
先从路由的as_view() 开始,
执行BookView类继承的APIView类里的as_view(),
而该as_view() 在内部重写了APIView类的父类View的as_view() 方法,
所以执行的是父类View的as_view(),
而View的as_view()方法在内部的返回值是dispatch()
该dispatch()是先从APIView类里查找,
因为APIView类有dispatch(),
所以最终执行的是APIView类的dispatch() 进行分发。
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):
# 构建新的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
# 初始化:认证、权限、限流组件三件套
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)
Serializer进行序列化和反序列化
数据库的数据到前端进行序列化
前端的数据上传到数据库进行反序列化
如果self.instance is not None执行update()
否则执行create() 分别对应put()和post()
但BaseSerializer类里的create()和update()必须重写
所以Bookserializers类里有这两个方法
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()),
]
已经将模型的字段在内部进行封装;
在内部已经重写create()和update();
1、GenericAPIView继承APIView类,self.get_serializer_class()等于Bookserializers
2、而self.get_serializer等于self.get_serializer_class()
3、self.get_queryset() 等于取出多条数据
4、self.get_object() 等于取出一条数据
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()
ListModelMixin的list方法对应BookView的get方法
CreateModelMixin的create方法对应BookView的post方法
RetrieveModelMixin的retrieve方法对应BookDetailView的get方法
UpdateModelMixin的update方法对应BookDetailView的put方法
DestroyModelMixin的destroy方法对应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)
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
BookView类继承六个类,其中GenericViewSet类继承的ViewSetMixin类实现了将路由传的字典映射到对应的方法,这样才可以将BookView和BookDetailView和成一个类,而继承的其他五个类对应了增删改查方法
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\d+)' , BookView.as_view({'get':'retrieve','delete':'destroy','put':'update'})),
]
ModelViewSet类继承了CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin,ListModelMixin,
GenericViewSet这六个类
views.py
# author xsy
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = Books.objects.all()
serializer_class = Bookserializers
urls.py
# author xsy
from rest_framework import routers
router = routers.DefaultRouter()
router.register('book',BookView)
urlpatterns = [
]
urlpatterns += router.urls