0x00 引言
本篇对 drf 中的 mixins 进行简要的分析总结.
Mixins 在 drf 中主要配合 viewset 共同使用, 实现 http 方法与 mixins 的相关类与方法进行关联.
from rest_framework import viewsets
在这个 viewset 中, 只要有 5 类 Minxin, 他们与 http 方法对应如下:
下面, 我们将逐个 Mixins 介绍!
- 0x01 CreateModelMixin
- # 源码
- 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)
- 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()
- 显然, 这不是唯一的解决方法, 我们还可以在 seriliazer 进行设置, 我们还可以使用 drf 的信号量进行解决!
- 0x02 ListModelMixin
- # 源码
- 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 一般用来获取列表页, 大多数情况下比较简单, 不需要重写相关的方法.
- 0x03 RetriveModelMixin
- # 源码
- 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)
- 对 retrieve 这个方法的重写几率比较高, 例如我们在增加点击数的时候, 经常要对其进行一个重写.
- 0x04 ReriveModelMixin
- # 源码
- 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)
- RetrieveModelMixin 的实现逻辑基本整合了 Create 以及 Retrieve, 先得到具体的实例, 再对其进行验证以及保存, 如果需要对更新这个逻辑进行自定义, 那么需要重写 perform_update( ) 方法, 而尽量少去重写 update( ).
- 0x05 DestoryModelMixin
- # 源码
- 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()
DestroyModelMixin 的逻辑也相对比较简单, 我们取 CreateModelMixin 下面的例子, 当我们取消收藏, 那么我们的 DestroyModelMixin 就发挥作用了. 同理
- def perform_create(self, serializer):
- instance = serializer.save()
- course = instance.course
- if course.fav_num> 0:
- course.fav_num -= 1
- else:
- course.fav_num = 0
- course.save()
0x05 小结
mixins 相对比较好理解, 本篇只是简要的分析了源码的内容以及各个 mixins 的逻辑, 最重要的还是学会去重写它们相关的方法.
一般情况下, 当我们在操作某一个 model 的时候, 涉及到另外一个 model 中数据的修改, 那么就需要对这个 mixins 下执行 save 的逻辑的方法进行重写.
来源: https://www.cnblogs.com/JetpropelledSnake/p/9403879.html