drf快速入门03--- 2个视图基类&5个视图mixins扩展类&9个GenericAPIView的视图子类&5个viewsets视图集基类---继承关系及部分源码精读

1. 继承关系

图片来源https://blog.csdn.net/LHQ626/article/details/118400296

2. GenericAPIView[通用视图类]

2.1. GenericAPIView介绍

a. 继承自APIVIew

b. 主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。

c. 通常在使用时,可搭配一个或多个Mixin扩展类。

2.2. 属性及方法介绍

属性

queryset 

指明表模型对象

serializer_class

指明视图使用的序列化器

 lookup_field = 'pk'

路由有名分组用的,这也就是有名分组,为什么只能填pk,
因为这里写死了,如果我们想要有名分组的变量,叫xxx
需要在外部视图配置一下
lookup_field = 'xxx'

filter_backends

# 默认内部查询的静态字段

filter_backends = api_settings.DEFAULT_FILTER_BACKENDS

pagination_class  

默认内部分页用的静态字段
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

方法

get_serializer_class(self)

外部使用
当出现一个视图类中调用多个序列化器时,
那么可以通过条件判断在get_serializer_class方法中,
通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。

# 当试图中使用多个序列化器类时,可以使用该方法来区分
class OrderView(CreateAPIView):
    def get_serializer_class(self):
        if self.request.method == 'GET':
            return StudentModelSerializer1
        return StudentModelSerializer2

    queryset = models.Order.objects.filter(is_deleted=False, is_show=True)
    serializer_class = get_serializer_class

    

 get_queryset(self)

一般内部使用,但是外部可以重写获得reuqest
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,
是列表视图与详情视图获取数据的基础,默认返回`queryset`属性。
重写帮助视图拿到request,比如可以用于ListAPIView
class OrderDataView(ListAPIView):
    """查询属于与自己的订单"""
    permission_classes = [IsAuthenticated, ]
    serializer_class = OrderDataModelSerializer

    def get_queryset(self):
        queryset = models.Order.objects.filter(user=self.request.user, is_deleted=False)

        return queryset

 get_object(self)

外部使用
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404.
# get_object()方法根据pk参数查找queryset中的数据对象
# 返回详情视图所需的模型类数据对象
# 就是get_object <==> models.UserInfo.object.filter(id=1).first()

该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
class BookDetailView(GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    def get(self, request, pk):
        book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
        serializer = self.get_serializer(book)
        return Response(serializer.data)

 get_serializer(self, *args, **kwargs)/get_serializer_context(self)

两个都是内部使用
get_serializer(self, *args, **kwargs)
其返回一个serializer_class
内部使用的,一般外部不用。
外部使用:self.get_serializer()()
调用封装request的方法,把request给封装进了context,
以后self.context.get('request'),就可以拿到request

def get_serializer(self, *args, **kwargs):
    serializer_class = self.get_serializer_class()
    kwargs.setdefault('context', self.get_serializer_context())
    return serializer_class(*args, **kwargs)

# get_serializer_context(self) 
# 封装request的方法
def get_serializer_context(self):
    return {
        'request': self.request,
        'format': self.format_kwarg,
        'view': self
    }

get_serializer_class

内部使用
外部配置的serializer_class,被其进行相关的处理
def get_serializer_class(self):
    assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method."
            % self.__class__.__name__
    )

    return self.serializer_class

filter_queryset(self, queryset)

# 内部使用
# 过滤用的,
def filter_queryset(self, queryset):
    for backend in list(self.filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, self)
    return queryset

paginate_queryset(self, queryset)

# 内部使用
# 分页处理
def paginate_queryset(self, queryset):
    if self.paginator is None:
        return None
    return self.paginator.paginate_queryset(queryset, self.request, view=self)

2.3. 基于GenericAPIView写的接口 

# views.py
class Book2View(GenericAPIView):
    #queryset要传queryset对象,查询了所有的图书
    # serializer_class使用哪个序列化类来序列化这堆数据
    queryset=Book.objects
    # queryset=Book.objects.all()
    serializer_class = BookSerializer
    def get(self,request):
        book_list=self.get_queryset()
        book_ser=self.get_serializer(book_list,many=True)

        return Response(book_ser.data)
    def post(self,request):
        book_ser = self.get_serializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status':101,'msg':'校验失败'})


class Book2DetailView(GenericAPIView):
    queryset = Book.objects
    serializer_class = BookSerializer
    def get(self, request,pk):
        book = self.get_object()
        book_ser = self.get_serializer(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({'status': 101, 'msg': '校验失败'})

    def delete(self,request,pk):
        ret=self.get_object().delete()
        return Response({'status': 100, 'msg': '删除成功'})
    
 #url.py
    # 使用GenericAPIView重写的
    path('books2/', views.Book2View.as_view()),
    re_path('books2/(?P<pk>\d+)', views.Book2DetailView.as_view()),

3. 5个视图扩展类mixins

3.1 mixins介绍

a. 提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,

b. 如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

c. 这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

3.2 mixins源码

CreateModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin,
ListModelMixin,


class ListModelMixin:
    """
    List a queryset.
    """
    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)


class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class UpdateModelMixin:
    """
    Update a model instance.
    """
    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):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            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)


class DestroyModelMixin:
    """
    Destroy a model instance.
    """
    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()

3.3 基于GenericAPIView和5个视图扩展类写的接口

from rest_framework.mixins import  ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# views.py
class Book3View(GenericAPIView,ListModelMixin,CreateModelMixin):

    queryset=Book.objects
    serializer_class = BookSerializer
    def get(self,request):
        return self.list(request)

    def post(self,request):
        return self.create(request)

class Book3DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
    queryset = Book.objects
    serializer_class = BookSerializer
    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)
# urls.py
    # 使用GenericAPIView+5 个视图扩展类  重写的
    path('books3/', views.Book3View.as_view()),
    re_path('books3/(?P<pk>\d+)', views.Book3DetailView.as_view()),

4 GenericAPIView的视图子类

4.1 GenericAPIView的子类介绍

a. 视图子类,也叫通用视图子类。

b. 继承了GenericAPIView,以及Mixin,真正的实现了几行代码,完成一个视图

c. 其实就是帮你,return了视图中手动return的方法

1)CreateAPIView

提供 post 方法

继承自: GenericAPIView、CreateModelMixin

2)ListAPIView

提供 get 方法

继承自:GenericAPIView、ListModelMixin

3)RetrieveAPIView

提供 get 方法

继承自: GenericAPIView、RetrieveModelMixin

4)DestoryAPIView

提供 delete 方法

继承自:GenericAPIView、DestoryModelMixin

5)UpdateAPIView

提供 put 和 patch 方法

继承自:GenericAPIView、UpdateModelMixin

6)RetrieveUpdateAPIView

提供 get、put、patch方法

继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

7)RetrieveUpdateDestoryAPIView

提供 get、put、patch、delete方法

继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

4.2 GenericAPIView的视图子类&Mixin书写接口

"""使用GenericAPIView的视图子类进一步简化开发api接口的代码"""
from rest_framework.generics import ListAPIView,CreateAPIView
class Students3GenericAPIView(ListAPIView,CreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer


from rest_framework.generics import RetrieveAPIView,UpdateAPIView,DestroyAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView # 结合了上面三个子类的功能
class Student3GenericAPIView(RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

5. 视图集基类viewsets

5.1 源码分析ViewSetMixin

# 重写了as_view
# 核心代码(所以路由中只要配置了对应关系,比如{'get':'list'}),当get请求来,就会执行list方法
for method, action in actions.items():
    #method:get
    # action:list
    handler = getattr(self, action)
    #执行完上一句,handler就变成了list的内存地址
    setattr(self, method, handler)
    #执行完上一句  对象.get=list
    #for循环执行完毕 对象.get:对着list   对象.post:对着create

5.2 继承ViewSetMixin的视图类

# views.py
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前
    def get_all_book(self,request):
        print("xxxx")
        book_list = Boaok.objects.all()
        book_ser = BookSerializer(book_list, many=True)
        return Response(book_ser.data)
    
# urls.py
    #继承ViewSetMixin的视图类,路由可以改写成这样
    path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),

5.3 viewsets数量

class ViewSet(ViewSetMixin, views.APIView):
    """
    The base ViewSet class does not provide any actions by default.
    """
    pass


class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass


class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    """
    A viewset that provides default `list()` and `retrieve()` actions.
    """
    pass


class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass

5.4 使用ModelViewSet快速编写5个接口

(看着玩就行,一般不用他,封装程度太高)

# 1. views.py  ViewSetMixin,APIView
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前
    def get_all_book(self,request):
        print("xxxx")
        book_list = Boaok.objects.all()
        book_ser = BookSerializer(book_list, many=True)
        return Response(book_ser.data)
    
# urls.py
    #继承ViewSetMixin的视图类,路由可以改写成这样
    path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),


"""2. ViewSet 使用视图集把上面的两个视图类组成一个视图类"""
from rest_framework.viewsets import ViewSet
class StudentViewSet(ViewSet):
    def get_all(self,request):
        """获取所有学生信息"""
        data_list = Student.objects.all()
        serializer = StudentModelSerializer(instance=data_list, many=True)
        return Response(serializer.data)

    def add_student(self,request):

        return Response({"message":"添加成功!"})

    def get_one(self,request,pk):
        """获取一个学生信息"""
        instance = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=instance)
        return Response(serializer.data)


# 3. ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView
"""发挥下ViewSet的作用"""
from rest_framework.viewsets import ViewSet
from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView
class Student2ViewSet(ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def get_all(self,request):
        """获取所有学生信息"""
        return self.list(request)

    def add_student(self,request):

        return self.create(request)

    def get_one(self,request,pk):
        """获取一个学生信息"""
        return self.retrieve(request)
# 4 GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin
class Student3ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def get_all(self,request):
        """获取所有学生信息"""
        return self.list(request)

    def add_student(self,request):

        return self.create(request)

    def get_one(self,request,pk):
        """获取一个学生信息"""
        return self.retrieve(request)

# 5 GenericViewSet,ListModelMixin,CreateModelMixin,
RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
"""简化上面的代码"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

# 6. views.py  ModelViewSet
from rest_framework.viewsets import ModelViewSet
class Book5View(ModelViewSet):  #5个接口都有,但是路由有点问题
    queryset = Book.objects
    serializer_class = BookSerializer
    
# urls.py
# 使用ModelViewSet编写5个接口
    path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #当路径匹配,又是get请求,会执行Book5View的list方法
    re_path('books5/(?P<pk>\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑猪去兜风z1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值