视图类与视图集的使用
一、视图类:View、APIView、GenericAPIView
View是Django提供的一个视图类,类的返回值需要用到HttpResponse、JSONResponse
(一)、APIView
继承自Django中定义的View,但和View有两个区别:
- 返回数据用到的是drf框架中的Response
- 对数据的处理上,可以通过query_params来代替GET,data来代替POST
# 创建加密分页类
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor'
page_size = 2
max_page_size = 4
max_page_size_param = 'size'
page_param = 'cursor'
ordering = 'id'
# 注意:加密分页类和其他的两个类的一个不同点在于,该类分页时需要排序,ordering = ‘字段’
class APIView1(APIView):
# 获取所有的数据
def get(self, request, *args, **kwargs):
role_obj = Role.objects.all()
pg = MyCursorPagination()
page = pg.paginate_queryset(queryset=role_obj, request=request, view=self)
serializer = Page2Serializer(instance=page, many=True)
return pg.get_paginated_response(serializer.data)
# 在数据库中创建一条数据
def post(self, request, *args, **kwargs):
data_dict = request.data
serializer = Page2Serializer(data=data_dict)
result = serializer.is_valid(raise_exception=True)
if result:
serializer.save()
# 创建和更新数据必须写.save()方法
return Response(serializer.validated_data)
class APIView2(APIView):
# 获取一条数据
def get(self, request, pk):
role_obj = Role.objects.get(pk=pk).first()
serializer = Page2Serializer(instance=role_obj)
return Response(serializer.data)
# 更新一条数据
def put(self, request, pk):
data_dict = request.data
serializer = Page2Serializer(data=data_dict)
result = serializer.is_valid(raise_exception=True)
# 注意:更新和创建都是反序列化操作,必须接收数据后进行数据的校验,然后再进行存储
if result:
serializer.save()
return Response(serializer.validated_data)
# 删除一条数据
def delete(self, request, pk):
role_obj = Role.objects.filter(pk=pk)
role_obj.delete()
return Response("删除成功")
(二)、GenericAPIView
GenericAPIView继承自APIView,和APIView的区别在于需要把用到的数据集和需要用到的组件中的类作为全局变量定义在视图类中使用。
# Create your views here.
class TestGenericAPIView(GenericAPIView):
queryset = UserInfo.objects.all()
serializer_class = UserInfoSerializer1
pagination_class = PageNumberPagination
# GenericAPIView与APIView和View的区别在与需要把实例化的数据集queryset和视图中要用到的组件类必须在方法前进行声明,作为全局变量来使用,在类方法中再进行调用
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
pg = self.paginate_queryset(queryset=queryset)
serializer = self.get_serializer(instance=pg, many=True)
return Response(serializer.data)
# GenericAPIView继承自APIView类,通过generic.py文件中的源码可以看出,该类封装了很多的方法,通过在类中定义的全局变量作为参数传递给类中的具体点方法,这些方法也只是返回获取到的类,并未对分页、序列化器等进行处理,这个功能的实现还是需要自己来来进行。和APIView没有太大的区别。
二、视图集的使用:GenericViewSet、ModelViewSet
Note
视图集的使用上和视图类有一个很重要的区别:视图集中可以自定义处理方法名,这些方法名必须声明在as_view({'request方式':'方法名'})内。视图集解决了视图类中的两个问题:
- 请求方式冲突的问题:在视图集中get请求既是获取所有的数据,即数据列表,也是获取单条数据,即数据详情,容易造成混乱
- url冲突:在视图类中有pk和没有pk参数的处理类是不同的,需要用到两个视图类,为两个类分别创建url,视图集中只需要创建一个视图类即可解决,并且视图集的使用中可以调用Router类来管理url,很好的解决了url的混乱问题。
(一)、GenericViewSet类的使用
该类继承自GenericAPIView和ViewSetMxixin两个类, 具有GenericAPIView中的所有属性和方法,同样也需要去通过self去获得所有的类和queryset,如果希望直接使用增删改查中的一些方法,则需要单独继承Mixins扩展中的类, 这些类在继承上必须优于GenericAPIView;如果不继承扩展类,则必须自定义处理方法
from rest_framework.viewsets import GenericViewSet
from rest_framework.pagination import CursorPagination
class MyPagination(CursorPagination):
page_size = 1
page_param = 'page'
max_page_size = 5
max_page_size_param = 'size'
ordering = 'id'
cursor_query_param = 'cursor'
# 自定义处理方法
class GenericViewSet1(GenericViewSet):
queryset = UserInfo.objects.all()
serializer_class = UserInfoSerializer1
# pagination_class = PageNumberPagination
pagination_class = MyPagination
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
pg = self.paginate_queryset(queryset=queryset)
serializer = self.get_serializer(instance=pg, many=True)
data = pg.get_paginated_response(serializer.data)
# GenericAPIView中所有的用法在该类中同样继承下来
return data
# 继承扩展类
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.viewsets import GenericViewSet
class View3View(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
queryset = Role.objects.all()
serializer_class = Page2Serializer
pagination_class = LimitOffsetPagination
(二)、ModelViewSet视图集的使用
Note
ModelViewSet类的使用中需要注意的是:一旦继承该类,在视图类中就不需要自定义request的请求方法, 该类把增删改查等基本的处理方法已经封装好了,直接继承Mixins扩展中的五个类,可以直接使用。优点是方便简介,可以直接使用。缺点是该类封装类绝大部分的方法,只有这些接口都需要用到的时候这个类才是最优选择,该类的可定制性不高。
--serializers.py
class Page2Serializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
def validate(self, data):
id = data.get('id')
title = data.get('title')
return data
# 若要执行创建和更新的操作,必须先从验证过的数据中获取对应的信息,然后再执行操作。
def create(self, validated_data):
id = validated_data.get('id')
title = validated_data.get('title')
instance = Role.objects.create(id=id, title=title)
instance.save()
return instance
def update(self, instance, validated_data):
id = validated_data.get('id')
title = validated_data.get('title')
instance = Role.objects.filter(id=id).first()
instance.id = id
instance.title = title
instance.save()
return instance
'''
需要特别注意的是:当序列化类继承的是Serializer的时候,除了字段验证之外,必须写上create和update饭方法,
'''
--views.py
class View2View(ModelViewSet):
queryset = Role.objects.all()
serializer_class = Page2Serializer
pagination_class = PageNumberPagination
因为基类中虽然有两个方法,但是都是pass,如果不重写两个方法,系统就是报错无法正常运行
三、Mixin的五个扩展类
ListModelMixin:这个扩展类的功能是获取数据列表
RetrieveModelMixin :这个扩展类的功能是获取某一条数据详情
CreateModelMixin : 这个扩展类的功能是在数据库中创建一条数据
UpdateModelMixin: 这个扩展类的功能是在数据库中更新一条数据
DestroyModelMixin:这个扩展类的功能是从数据库中删除指定的一条数据
四、视图类和视图集的关系图
Note
越是封装内容多的类,可定制性、灵活性越差,功能越全面,越是基类可定制性越高,但很多的方法和功能需要开发者定义