DRF之视图
一、基于APIView的五个接口
首先,APIView是Rest Framework提供的所有视图的基类,继承了Django的View
其次,APIView和View的不同在于:
- 他们传入视图方法中的request对象不是同一个,APIView的是Request对象,View的是HttpResponse对象。
- APIView返回的是Response对象,是符合前端Accept要求的格式
- 在dispatch分发前会进行身份认证,权限检查,流量控制
五个接口实例:
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.ser import BooksSerializers
from app01.models import Books
# 基于APIView
class BooksView(APIView):
# 查所有
def get(self, request):
books = Books.objects.all()
books_ser = BooksSerializers(instance=books, many=True)
return Response(books_ser.data)
# 增加
def post(self, request):
books_ser = BooksSerializers(data=request.data)
if books_ser.is_valid():
books_ser.save()
return Response(books_ser.data)
class BookView(APIView):
# 查单个
def get(self, request, pk):
print(pk, type(pk))
book = Books.objects.filter(pk=pk).first()
book_ser = BooksSerializers(instance=book)
return Response(book_ser.data)
# 修改
def put(self, request, pk):
book = Books.objects.filter(pk=pk).first()
book_ser = BooksSerializers(instance=book, data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({'message': book_ser.errors})
# 删除
def delete(self, request, pk):
Books.objects.filter(pk=pk).delete()
return Response({'message': '删除成功'})
# urls.py
path('books/', views.BooksView.as_view()),
re_path(r'^book/(?P<pk>\d+)/', views.BookView.as_view()),
二、基于GenericAPIView的五个接口
首先,GenericAPIView继承了APIView,并增加了操作序列化器和数据库查询方法
并提供了两个属性和两个方法
queryset:
指要传的queryset对象
get_queryset():
返回queryset对象
serializer_class:
指明视图使用的序列化器,也就是哪个序列化类来序列化这堆数据
get_serializer():
返回序列化器类
get_object():
返回视图所需的模型类数据对象
源码如下:
# from rest_framework.generics import GenericAPIView
class GenericAPIView(views.APIView):
queryset = None # 指要传的queryset对象
serializer_class = None # 指明视图使用的序列化器,也就是哪个序列化类来序列化这堆数据
......
def get_queryset(self):
......
queryset = self.queryset
# 判断传入的queryset是不是QuerySet的对象
if isinstance(queryset, QuerySet):
queryset = queryset.all() # 是就加all()——>Book.objects.all()
return queryset # 返回queryset对象
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
# 向序列化器对象的context属性补充三个数据,
# request,当前视图的请求对象
# format,当前请求的类视图对象
# view,当前请求期望返回的数据格式
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs) # 返回序列化器类
五个接口实例:
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from app01.ser import BooksSerializers
from app01.models import Books
# 基于GenericAPIView
class BooksView(GenericAPIView):
queryset = Books.objects
serializer_class = BooksSerializers
# 查所有
def get(self, request):
books = self.get_queryset() # 相当于Books.objects.all()
books_ser = self.get_serializer(instance=books, many=True)
return Response(books_ser.data)
# 新增
def post(self, request):
books_ser = self.get_serializer(data=request.data)
if books_ser.is_valid():
books_ser.save()
return Response(books_ser.data)
class BookView(GenericAPIView):
queryset = Books.objects
serializer_class = BooksSerializers
# 查单个
def get(self, request, pk):
book = self.get_object()
book_ser = self.get_serializer(instance=book)
return Response(book_ser.data)
# 修改
def put(self, request, pk):
book = self.get_object()
book_ser = self.get_serializer(instance=book, data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({'message': book_ser.errors})
# 删除
def delete(self, request, pk):
self.get_object().delete()
return Response({'message': '删除成功'})
三、GenericAPIView的五个视图括展类
因为之前代码的处理流程重复代码太多,所以可以使用相应的扩展类来减少编写的代码量。
而这五个扩展类需要搭配GenericAPIView父类,并且还要调用GenericAPIView提供的序列化器和数据查询方法。
ListModeMixin
列表视图扩展类(类似于查询所有),提供了快速获取所有列表的视图,并且该方法会对数据进行过滤和分页,成功返回200
源代码:
class ListModelMixin:
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) # 返回序列化后的数据
CreateModeMixin
创建视图扩展类(创建数据),提供了快速创建资源的视图,成功返回201,失败400
原代码:
class CreateModelMixin:
# 创建模型实例
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 {}
RetrieveModelMixin
详情视图扩展类(查询单个),返回一个存在的数据对象,成功返回201,失败404
原代码:
class RetrieveModelMixin:
def retrieve(self, request, *args, **kwargs):
# 获取对象,并检查对象的权限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance)
return Response(serializer.data)
UpdateModelMixin
更新视图扩展类(更新数据),快速更新一个存在的数据对象,也可实现局部更新 partial_update() 成功返回201,失败400
源代码
class UpdateModelMixin:
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):
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)
DestroyModelMixin
删除视图扩展类(删除数据),快速删除一个存在的数据对象,成功返回204,不存在返回404。
源代码
class DestroyModelMixin:
def destroy(self, request, *args, **kwargs):
# 获取对象
instance = self.get_object()
# 删除对象
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
五个视图扩展类的使用实例
from rest_framework.generics import GenericAPIView
from app01.ser import BooksSerializers
from app01.models import Books
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
# 基于GenericAPIView的五个视图扩展类
class BooksView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Books.objects
serializer_class = BooksSerializers
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookView(GenericAPIView, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
queryset = Books.objects
serializer_class = BooksSerializers
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)
四、GenericAPIView的视图子类
二话不说先来看其中一个源码!!!其他的子类都是一样的原理
源码
# 首先它继承了CreateModelMixin创建视图扩展类
class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):
# 并且它提供了post方法,那我们就不用在视图中写post方法了,这里直接写好了直接调用self.create
# 只需要传入对象和序列化器就可以了
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
实例:
from rest_framework.generics import ListAPIView, UpdateAPIView
from rest_framework.generics import CreateAPIView, DestroyAPIView, RetrieveAPIView
from app01.ser import BooksSerializers
from app01.models import Books
# 基于GenericAPIView的五个视图子类
class BooksView(ListAPIView, UpdateAPIView): # 获取所有,修改一个
queryset = Books.objects
serializer_class = BooksSerializers
# 获取一个,更新一个,删除一个
class BookView(CreateAPIView, DestroyAPIView, RetrieveAPIView):
queryset = Books.objects
serializer_class = BooksSerializers
GenericAPIView的视图子类除了这五个还有四个,也就是这五个方法的其他组合:
- ListCreateAPIView
- 提供get、post方法,是 ListAPIView 和 UpdateAPIView 的组合
- RetrieveDestroyAPIView
- 提供get、delete方法,是 RetrieveAPIView 和 DestroyAPIView 的组合
- RetrieveUpdateAPIView
- 提供get、update方法,是 RetrieveAPIView 和 UpdateAPIView 的组合
- RetrieveUpdateDestroyAPIView
- 提供get、update、delete方法,是 RetrieveAPIView 、 UpdateAPIView 和 DestroyAPIView 的组合
五、ModelViewSet
首先它继承了 GenericViewSet,并且还有 ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
ModelViewSet五个接口
先来看一下它的使用:
# views.py
from rest_framework.viewsets import ModelViewSet
from app01.ser import BooksSerializers
from app01.models import Books
class BooksView(ModelViewSet): # 五个接口都有
queryset = Books.objects
serializer_class = BooksSerializers
# urls.py
from django.contrib import admin
from django.urls import path, re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 当路径匹配,又是get请求,会执行BooksView的list方法
path('books/', views.BooksView.as_view({'get': 'list', 'post': 'create'})),
re_path(r'^book/(?P<pk>\d+)/', views.BooksView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
]
源码分析
由于 ModelViewSet 继承了 GenericViewSet ,并且 GenericViewSet 又继承了 ViewSetMixin,ViewSetMixin中又重写了 as_view 方法, 也就是说当路径匹配上了会执行这里重写的 as_view 方法。
分析: as_view 方法
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
...
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# 核心代码,所有路由中只要配置了对应关系,比如{'get': 'list'},当get请求来,就会执行list方法
for method, action in actions.items():
# 遍历我们传入的对应关系
# method = get
# action = list
# 并且通过反射获取list方法的内存地址
handler = getattr(self, action) # handler已经是list的内存地址
# 点拦截(对象.get = list)
setattr(self, method, handler)
# 当循环完毕之后,对象.get:对应list方法,对象.post:对应create方法
...
# 后面照常继续
return self.dispatch(request, *args, **kwargs)
继承ViewSetMixin的视图类
由上面的分析可以得出,我们也可以直接继承 ViewSetMixin 写视图,如下:
from rest_framework.viewsets import ViewSetMixin
from rest_framework.response import Response
from app01.ser import BooksSerializers
from app01.models import Books
class BooksView(ViewSetMixin, APIView):
def get_all_books(self, request):
book_list = Books.objects.all()
book_ser = BooksSerializers(book_list, many=True)
return Response(book_ser.data)
# urls.py
# 当匹配上了路由,又是get请求,就调用get_all_books方法
path('books/', views.BooksView.as_view({'get': 'get_all_books'})),
本文来自博客园,作者:Mr-Yang`,转载请注明原文链接:https://www.cnblogs.com/XiaoYang-sir/p/14988276.html