Django Rest Framework(第三天)-mixins模块源码分析

2.3 mixins模块源码分析

既然讲到这里,使用了mixins,那么不得不讲讲源码: class CreateModelMixin(object):增加 class ListModelMixin(object):展示数据列表 class RetrieveModelMixin(object):展示单条数据 class UpdateModelMixin(object):更新单条数据 class DestroyModelMixin(object):删除单条数据

在分析源码前,我们先来了解多重继承的一个知识点

class A:
    def a(self):
        print("A")
        self.b()
class B:
    def b(self):
        print("B")
class D(A,B):
    pass
d = D()
d.a()

会输出AB 类D多重继承AB,类D实例对象d.a()时候,如果在类A中找不到b()方法,它就会在多重继承的AB类中,横向寻找b方法,结果在类B中找到,然后输出

2.3.1 mixins.ListModelMixin

def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

我们可以看到,这个方法直接返回了self.list(request, args, *kwargs),它会理所应当的去多重继承的父类中寻找方法,然后跟踪代码,我们可以看到进入了:

class ListModelMixin(object):
    """
    List a queryset.==> 列表页获取
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        # 这是一个分页功能,如果在viewset中设置了pagination_class,那么这里就会起作用
        # 获取当前页的queryset,如果不存在分页,返回None
        page = self.paginate_queryset(queryset)

        if page is not None:
        # 分页不为空,那么不能简单的执行Response(serializer.data)
        # 还需要将相关的page信息序列化在进行响应
            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)

ListModelMixin一般用来获取列表页,大多数情况下比较简单,不需要重写相关的方法。

2.3.2 mixins.CreateModelMixin

创建视图扩展类,提供create(request, args, *kwargs)方法快速实现创建资源的视图,成功返回201状态码。

如果序列化器对前端发送的数据验证失败,返回400错误。

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

我们可以看到,这个方法直接返回了self.create(request, args, *kwargs),它会理所应当的去多重继承的父类中寻找方法,然后跟踪代码,我们可以看到进入了:

class CreateModelMixin(object):
    """
    Create a model instance ==>创建一个实例
    """
    def create(self, request, *args, **kwargs):
    # 获取相关serializer
        serializer = self.get_serializer(data=request.data)

        # 进行serializer的验证
        # raise_exception=True,一旦验证不通过,不再往下执行,直接引发异常
        serializer.is_valid(raise_exception=True)

        # 调用perform_create()方法,保存实例
        self.perform_create(serializer)

        # 用户Token验证,并且通过return {'Location': str(data[api_settings.URL_FIELD_NAME])}保存一个临时头部数据,最后 

# 将序列化的数据,响应状态码(201 Created:请求已经被实现)、头部一并返回即可

        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 {}

由上图可以看出这个类的一个逻辑,其中,perform_create( )对serializer直接进行save保存,当在一些情境下,我们需要对perform_create( )进行重写。 那么我们现在可能有一个下面的需要:

假设现在有一个course课程model,里面维持了一个数,记录课程收藏数,还存在一个用户收藏userfav的model(应当有一个外键指向course),当一个用户对课程进行收藏,理论上现在post进来的应该是userfav的instance,显然,我们还需要对相应course的收藏数进行+1。 这个时候,我们就需要重写perform_create( )方法!

def perform_create(self, serializer):
# 重写save的逻辑
    instance = serializer.save()
    course = instance.course
    course.fav_num += 1
    course.save()

2.3.3 mixins.RetrieveModelMixin

详情视图扩展类,提供retrieve(request, args, *kwargs)方法,可以快速实现返回一个存在的数据对象。

如果存在,返回200, 否则返回404。

queryset = Snippet.objects.all()
serializer_class = SnippetSerializer

def get(self, request, *args, **kwargs):
    return self.retrieve(request, *args, **kwargs)

执行get方法也是从GenericAPIView多重继承类中获取get_object,然后进行序列化,最后 return Response(serializer.data)返回即可.

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.==> 获取某一个对象的具体信息
    """
    def retrieve(self, request, *args, **kwargs):
        # 一般访问的url都为/obj/id/这种新式
        # get_object()可以获取到这个id的对象
        # 注意在viewset中设置lookup_field获取重写get_object()方法可以指定id具体对象是什么~!
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

2.3.4 mixins.UpdateModelMixin

更新视图扩展类,提供update(request, args, *kwargs)方法,可以快速实现更新一个存在的数据对象。

同时也提供partial_update(request, args, *kwargs)方法,可以实现局部更新。

成功返回200,序列化器校验数据失败时,返回400错误。

def put(self, request, *args, **kwargs):
    return self.update(request, *args, **kwargs)

UpdateModelMixin实现逻辑基本整合了Create以及Retrieve,先得到具体的实例,再对其进行验证以及保存,如果需要对更新这个逻辑进行自定义,那么需要重写perform_update( )方法,而尽量少去重写update( )

class UpdateModelMixin(object):
    """
    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)

2.3.5 mixins.DestroyModelMixin

删除视图扩展类,提供destroy(request, args, *kwargs)方法,可以快速实现删除一个存在的数据对象。

成功返回204,不存在返回404。

def delete(self, request, *args, **kwargs):
    return self.destroy(request, *args, **kwargs)

通过pk(或者其他标识)获取要删除的数据,然后instance.delete()删除,最后返回return Response(status=status.HTTP_204_NO_CONTENT)

class DestroyModelMixin(object):
    """
    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()

2.3.6 GenericAPIView

在APIView源码分析,分析了APIView的大概执行流程,我们先看下多重继承类中的

generics.GenericAPIView,看看它跟APIView有何关联?点开源码,原来GenericAPIView类是APIView的子类,继而扩充了一些其他的方法,我举出如下几个方法

get_queryset:提供方法,用来获取request请求封装完毕的结果集 get_object:获取单条数据 get_serializer:获取序列化后的数据 get_serializer_class:获取需要序列化的model类 get_serializer_context:获取序列化的数据,定义了某种格式的字典 paginator:分页器

2.3.7 generics

class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

跟踪源码可以看到generics.ListCreateAPIView也是继承自mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView

class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
    """
    Concrete view for listing a queryset or creating a model instance.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

2.3.8 总结

接口一般继承 generics 模块里面的以下这些类就行了,如果对get 、post 等方法有特殊的要求可以自己继承后重写 get、post 方法。

generics 模块里面有 :

2.3.8.1 GenericAPIView

不提供 get 、 post 等方法, 要跟 mixins 中的模块一起继承才能使用 get 、 post 等方法

2.3.8.2 CreateAPIView

提供 post 方法,用来【创建数据】。 继承自 mixins.CreateModelMixin 和 GenericAPIView

2.3.8.3 ListAPIView

提供 get 方法,用来【获取数据集合】。 继承自 mixins.ListModelMixin 和 GenericAPIView

2.3.8.4 RetrieveAPIView

提供 get 方法,用来【获取单条数据】。 继承自 mixins.RetrieveModelMixin 和 GenericAPIView

2.3.8.5 DestroyAPIView

提供 delete 方法,用来【删除单条数据】 继承自 mixins.DestroyModelMixin 和 GenericAPIView

2.3.8.6 UpdateAPIView

提供 put 和 patch 方法, 用来【修改单条数据】 继承自 mixins.UpdateModelMixin 和 GenericAPIView

2.3.8.7 ListCreateAPIView :

提供 get 和 post 方法,用来【获取数据集合】 和 【创建数据】 继承自 mixins.ListModelMixin,mixins.CreateModelMixin,和GenericAPIView

2.3.8.8 RetrieveUpdateAPIView

提供 get 、 put 和 patch 方法,用来【获取】和【修改】单条数据 继承自 mixins.RetrieveModelMixin,mixins.UpdateModelMixin,和GenericAPIView

2.3.8.9 RetrieveDestroyAPIView

提供 get 和 delete 方法,用来【获取】和【删除】单条数据 继承自 mixins.RetrieveModelMixin,mixins.DestroyModelMixin,和GenericAPIView

2.3.8.10 RetrieveUpdateDestroyAPIView

提供 get 、 put、 patch 和 delete 方法,用来【获取】、【修改】和【删除】单条数据 继承自 mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,和GenericAPIView

mixins相对比较好理解,本篇只是简要的分析了源码的内容以及各个mixins的逻辑,最重要的还是学会去重写它们相关的方法。    一般情况下,当我们在操作某一个model的时候,涉及到另外一个model中数据的修改,那么就需要对这个mixins下执行save的逻辑的方法进行重写。


评论(0 ) 点赞(14)


暂未登录,请登录之后发表评论。 QQ