DRF之视图类
视图基类
DRF视图类中除了APIView类,还有一个GenericAPIView类。
GenericAPIView类主要给我们提供了2个属性,3个方法。
2个属性:
- queryset:要序列化的数据
- serializer_class:序列化类
3个方法:
- get_queryset():获取要序列化的数据
- get_object():根据条件获取对象
- get_serializer():获取序列化类
CBV使用(第一层)
from rest_framework.generics import GenericAPIView
# 查询所有数据、添加数据接口
class BookView(GenericAPIView):
"""重写属性"""
# 数据库数据
queryset = models.Book.objects.all()
# 序列化类
serializer_class = serializer.BookSerializer
def get(self, request):
"""使用父类方法获取属性"""
book_list = self.get_queryset()
ser = self.get_serializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
"""使用父类方法获取属性"""
ser = self.get_serializer(data=request.data)
if ser.is_vaild():
ser.save()
return Response({'code': 100, 'msg': '添加成功'})
return Response({'code': 99, 'msg': '添加失败'})
# 查询一个数据、修改数据、删除数据接口
class BookDetailView(GenericAPIView):
"""重写属性"""
# 数据库数据
queryset = models.Book.objects.all()
# 序列化类
serializer_class = serializer.BookSerializer
def get(self, request, *args, **kwargs):
"""使用父类方法获取属性"""
book_obj = self.get_object()
ser = self.get_serializer(instance=book_obj)
return Response(ser.data)
def put(self, request, *args, **kwargs):
...
def delete(self, request, *args, **kwargs):
...
路由配置:转换器传的参数名一定要是'pk'。
path('books/', views.BookView.as_view()),
path('books/<int:pk>', views.BookDetailView.as_view())
GenericAPIView类是不是感觉没有比APIView类方便?别急,这只是前戏!
视图扩展类
DRF里还有5个视图拓展类,可以实现我们的五个接口。
from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin
ListModelMixin类
提供查询所有数据的方法:
RetrieveModelMixin类
提供查询单个数据的方法:
CreateModelMixin类
提供添加数据的方法:
UpdateModelMixin类
提供更新数据的方法:
DestroyModelMixin类
提供删除数据的方法:
CBV使用(第二层)
from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin
from rest_framework.generics import GenericAPIView
# 查询所有数据、添加数据接口
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
"""重写属性"""
# 获取数据库数据
queryset = models.Book.objects.all()
# 获取序列化类
serializer_class = serializer.BookSerializer
def get(self, request):
"""调用父类的list方法,也就是ListModelMixin中的方法"""
return super().list(request)
def post(self, request):
"""调用父类的create方法,也就是CreateModelMixin中的方法"""
return super().create(request)
# 查询一个数据、修改数据、删除数据接口
class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
"""重写属性"""
# 获取数据库数据
queryset = models.Book.objects.all()
# 获取序列化类
serializer_class = serializer.BookSerializer
def get(self, request, *args, **kwargs):
"""调用父类的retrieve方法,也就是RetrieveModelMixin中的方法"""
return super().retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
"""调用父类的update方法,也就是UpdateModelMixin中的方法"""
return super().update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
"""调用父类的destroy方法,也就是DestroyModelMixin中的方法"""
return super().destroy(request, *args, **kwargs)
现在代码是不是看起来少了一些了?这才第二层,继续往下!
视图子类
DRF提供了9个视图子类,稍微帮我们封装了一下代码。
# 提供查询所有接口
from rest_framework.generics import ListAPIView
# 提供添加单个接口
from rest_framework.generics import CreateAPIView
# 提供查询所有和添加单个接口
from rest_framework.generics import ListCreateAPIView
# 提供查询单个接口
from rest_framework.generics import RetrieveAPIView
# 提供修改单个接口
from rest_framework.generics import UpdateAPIView
# 提供删除单个接口
from rest_framework.generics import DestroyAPIView
# 提供查询单个和修改单个接口
from rest_framework.generics import RetrieveUpdateAPIView
# 提供查询单个和删除单个接口
from rest_framework.generics import RetrieveDestroyAPIView
# 提供查询单个和修改单个和删除单个接口
from rest_framework.generics import RetrieveUpdateDestroyAPIView
这9个视图子类仅仅只帮我们做了个封装,之后我们编写CBV时去继承这9个试图子类。
CBV使用(第三层)
from rest_framework.generics import RetrieveUpdateDestroyAPIView
from rest_framework.generics import ListCreateAPIView
# 查询所有数据、添加数据接口
class BookView(ListCreateAPIView):
"""重写属性"""
# 获取数据库数据
queryset = models.Book.objects.all()
# 获取序列化类
serializer_class = serializer.BookSerializer
# 查询一个数据、修改数据、删除数据接口
class BookDetailView(RetrieveUpdateDestroyAPIView):
"""重写属性"""
# 获取数据库数据
queryset = models.Book.objects.all()
# 获取序列化类
serializer_class = serializer.BookSerializer
现在是不是代码量骤降?现在才第三层,下面还有!
视图集
视图集,顾名思义,就是视图的集合。
DRF视图集中主要有五个类:
from rest_framework.viewsets import ViewSetMixin
from rest_framework.viewsets import ViewSet
from rest_framework.viewsets import GenericViewSet
from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import ReadOnlyModelViewSet
ViewSetMixin类
主要提供了一个不一样的as_view()方法,让我们可以在路由层做一些映射关系。
ViewSet类
继承了ViewSetMiXin类和APIView类。
GenericViewSet类
继承了ViewSetMiXin类和GenericAPIView类
ModelViewSet类
继承了ViewSetMixin类和5个视图拓展类,拥有了list、retrieve、update、create、destroy方法。
ReadOnlyModelViewSet类
继承了ViewSetMixin类和2个视图拓展类,拥有了list、retrieve方法。
CBV使用(第四层)
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
因为没有请求方法的编写,所以我们要去路由层添加映射关系:
# 路由层
urlpatterns = [
path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
我们甚至可以给CBV添加除请求方法以外的函数:
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
def login(self, request):
return Response('login')
路由层:
# 路由层
urlpatterns = [
path('books/', views.BookView.as_view({'get': 'login'})),
]
这样就会在浏览器发送get请求时执行视图类中的login方法。
视图类继承图
ViewSetMixin类解析
ViewSetMixin类提供了一个新的as_view()方法,我们可以查看源码看看具体是怎么实现的。
首先提供了一个actions参数,用于接收映射关系。
其次是下面图片中的红框部分。
假设在路由配置了如下映射:
as_view({'get': 'list', 'post': 'create'})
这时acitons的值为:
{'get': 'list', 'post': 'create'}
图片红框部分遍历了actions:
# 遍历actions
for method, action in actions.items():
"""
method的值依次为:get、post
action的值依次为:list、create
"""
# 先获取list、create方法
handler = getattr(self, action)
# 通过反射将get方法映射成list方法...
setattr(self, method, handler)