Mixin 类编写视图
我们这里用 auther 表来做演示, 先为 auther 和 autherdetail 写 2 个 url
- url(r'^autherdetail/(?P<id>\d+)', views.Book_detail_cbv.as_view(), name="autherdetail"),
- url(r'^auther/', views.Book_cbv.as_view(),name="auther"),
然后分别为这 2 个类写对应的序列化的类
- class authermodelserializer(serializers.ModelSerializer):
- class Meta:
- model = models.Auther
- fields = "__all__"
下面我们开写视图函数
需要在 view 文件中导入 2 个模块
- from rest_framework import mixins
- from rest_framework import generics
先介绍一下 mixins 类, 我们主要用 mixins 类来对 queryset 对象或者 model 对象做操作
mixins.ListModelMixin
这个是用来显示 queryset 的数据
mixins.CreateModelMixin
这个用来创建一条 model 对象
mixins.RetrieveModelMixin
这个是用来显示一个 model 对象
mixins.DestroyModelMixin
这个是用来删除一个 model 对象
mixins.UpdateModelMixin
这个是用来更新一个 model 对象
下面我们一个一个来看下面的类
1, 看下 mixins.ListModelMixin
这个类就只有一个方法, list 方法, 我们看下面的代码其实很熟悉, 就是把一个 queryset 对象做序列化后, 然后把序列化后的结果返回
- class ListModelMixin(object):
- """
- 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)
我们这里看到 get_serializer 中的参数有个 queryset, 那么这个 queryset 是什么呢?
通过上面的图, 我们大致可以猜到, 是由 self.get_queryset() 这个方法返回的结果, 那么这个方法又干了什么呢?
首先我们要清楚 self 是什么?
从上面的图我们知道, self 其实就是 Auther_view 这个类的实例对象, 这个实例对象根本就没有 get_queryset 这个方法, 但是由于这个类继承了 3 个类, 我们一个一个找, 最终在
generics.GenericAPIView 这个类中找到了 get_queryset 这个方法
- def get_queryset(self):
- """
- Get the list of items for this view.
- This must be an iterable, and may be a queryset.
- Defaults to using `self.queryset`.
- This method should always be used rather than accessing `self.queryset`
- directly, as `self.queryset` gets evaluated only once, and those results
- are cached for all subsequent requests.
- You may want to override this if you need to provide different
- querysets depending on the incoming request.
- (Eg. return a list of items that is specific to the user)
- """
- assert self.queryset is not None, (
- "'%s' should either include a `queryset` attribute, ""or override the `get_queryset()` method."
- % self.__class__.__name__
- )
- queryset = self.queryset
- if isinstance(queryset, QuerySet):
- # Ensure queryset is re-evaluated on each request.
- queryset = queryset.all()
- return queryset
我们可以很清晰的看到 get_queryset 这个方法返回的结果就是 self.queryset
那么 self.queryset 这个是什么呢?
我们在 Auhter_view 这个类中已经定义了这个类变量, 所以我们这里定义的 2 个类变量的名称是固定的, 不能随意修改的, 属于配置项
下面我们走的流程就和之前差不多了
先定义 get 请求的处理的函数
因为 mixins.ListModelMixin 这个类是为了显示 queryset 对象的类, 那么下面我们进入这个类
所以我们在 get 方法中, 直接调用 list 方法的返回结果就是我们想要的结果
2, 在来看 mixin.CreateModelMixin 类
这个类是为了创建一个 model 对象
首先进入这个类, 看下具体的代码
- class CreateModelMixin(object):
- """
- Create a model instance.
- """
- def create(self, request, *args, **kwargs):
- serializer = self.get_serializer(data=request.data)
- serializer.is_valid(raise_exception=True)
- 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 {}
下面我们来分析一下代码
首先这里有个 self.get_serializer 方法, 这个方法也在 generics.GenericAPIView 类中
下面我们在来看下 get_serializer 方法
- def get_serializer(self, *args, **kwargs):
- """
- Return the serializer instance that should be used for validating and
- deserializing input, and for serializing output.
- """
- serializer_class = self.get_serializer_class()
- kwargs['context'] = self.get_serializer_context()
- return serializer_class(*args, **kwargs)
我们在来看下 get_serializer_class 这个方法
我们看到非常清楚, 这个函数的返回值就是我们先前定义个 serializer_class 的类变量, 所以这个类变量的名称也不能修改, 必须要这么写, 属于一个配置类的变量
流程我们已经梳理清楚了, 下面我们在看下 post 请求的视图函数
post 请求调用的 mixins.CreateModelMixin 类中的 create 方法
- class CreateModelMixin(object):
- """
- Create a model instance.
- """
- def create(self, request, *args, **kwargs):
- serializer = self.get_serializer(data=request.data)
- serializer.is_valid(raise_exception=True)
- self.perform_create(serializer)
- headers = self.get_success_headers(serializer.data)
- return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
最后我们在看下 perform.create 这个方法, 是不是很熟悉了, 调用 save 方法保存
3, 然后来看下 mixins.RetriveModelMixin 类
先看下这个类的代码
- class RetrieveModelMixin(object):
- """
- Retrieve a model instance.
- """
- def retrieve(self, request, *args, **kwargs):
- instance = self.get_object()
- serializer = self.get_serializer(instance)
- return Response(serializer.data)
然后在来看下 get_object 这个方法干了什么, 这个方法同样在 generics.GenericAPIView 类中, 我们一猜就知道这个方法是获取一个 model 对象, 然后对这个 model 对象进行序列化处理
- def get_object(self):
- """
- Returns the object the view is displaying.
- You may want to override this if you need to provide non-standard
- queryset lookups. Eg if objects are referenced using multiple
- keyword arguments in the url conf.
- """
- queryset = self.filter_queryset(self.get_queryset())
- # Perform the lookup filtering.
- lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
- assert lookup_url_kwarg in self.kwargs, (
- 'Expected view %s to be called with a URL keyword argument'
- 'named"%s". Fix your URL conf, or set the `.lookup_field`'
- 'attribute on the view correctly.' %
- (self.__class__.__name__, lookup_url_kwarg)
- )
- filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
- obj = get_object_or_404(queryset, **filter_kwargs)
- # May raise a permission denied
- self.check_object_permissions(self.request, obj)
- return obj
我们看到这个方法确实返回一个 obj 对象
最后看下 get 请求, 调用 mixins.RetrieveModelMixin 类中的 retieve 方法返回我们要查询的结果
4, 然后我们在看下 mixins.DestroyModelMixin 类
直接拿到 model 独享, 然后调用 perform_destory 方法删除这个 model 对象
- 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()
然后我们在看下视图函数中是如何处理 delete 请求的
- class Autherdetail_view(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
- queryset = models.Auther.objects.all()
- serializer_class = authermodelserializer
- def get(self,request,*args,**kwargs):
- return self.retrieve(request,*args,**kwargs)
- def delete(self,request,*args,**kwargs):
- return self.destroy(request,*args,**kwargs)
直接返回 mixins.DestoryModelMixins 的 detory 函数的返回值就可以了
5, 最后看下 mixins.UpdateModelMixin 类
同样, 先获取 model 对象, 然后获取序列化类, 然后把 model 对象和 request.data 一起传递给序列化类
序列化类在调用调用 sava 方法保存数据
- 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)
我们在看 put 请求的视图函数
- class Autherdetail_view(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
- queryset = models.Auther.objects.all()
- serializer_class = authermodelserializer
- def get(self,request,*args,**kwargs):
- return self.retrieve(request,*args,**kwargs)
- def delete(self,request,*args,**kwargs):
- return self.destroy(request,*args,**kwargs)
- def put(self,request,*args,**kwargs):
- return self.update(request,*args,**kwargs)
来源: https://www.cnblogs.com/bainianminguo/p/10463741.html