zoukankan      html  css  js  c++  java
  • DRF的内置分页和筛选功能

    DRF中有内置的serializer序列化

    urls.py
    url(r'^page/view/article/$', views.PageViewArticleView.as_view()),
    
    
    views.py
    from rest_framework.generics import ListAPIView 
    class PageViewArticleSerializer(serializers.ModelSerializer): 
        class Meta: 
            model = models.Article 
            fields = "__all__" class 
    class PageViewArticleView(ListAPIView): 
        queryset = models.Article.objects.all() 
        serializer_class = PageViewArticleSerializer    ##内置序列化功能,但是序列化函数和功能需要自己定义
    
    
    

    小知识扩展:类的约束

    # 约束子类中必须实现f1方法
    class Base(object): 
        def f1(self): 
            raise NotImplementedError('asdfasdfasdfasdf') 
    class Foo(Base): 
        def f1(self): 
            print(123) 
    obj = Foo() 
    obj.f1()
    

    分页

    PageNumberPagination

    分页功能使用方式一

    • 配置settings.py
    REST_FRAMEWORK = { 
      "PAGE_SIZE":2
    }
    
    
    • 在视图的列表页面
    from rest_framework.pagination import PageNumberPagination 
    from rest_framework import serializers 
    class PageArticleSerializer(serializers.ModelSerializer):
      class Meta: 
      model = models.Article
        fields = "__all__" 
    class PageArticleView(APIView):
        def get(self,request,*args,**kwargs): 
          queryset =models.Article.objects.all()
            # 方式一:仅数据 
            """ 
            # 分页对象 
            page_object = PageNumberPagination() 
            
            # 调用 分页对象.paginate_queryset方法进行分页,得到的结果是分页之后的数据 
            # result就是分完页的一部分数据 
            result = page_object.paginate_queryset(queryset,request,self)
            
            # 序列化分页之后的数据
            ser = PageArticleSerializer(instance=result,many=True) 
            return  Response(ser.data) 
            """
    
            #方式二:数据+分页信息 
            """
            page_object=PageNumberPagination()
            result=page_object.paginate_queryset(queryset,request,self)
            ser=PageArticleSerializer(instance=result,many=True)
            return  page_object.get_paginated_response(ser.data)
            """
    
            #方式三:数据+部分分页信息
          page_object=PageNumberPagination()
          result=page_object.paginate_queryset(queryset,request,self)
          ser=PageArticleSerializer(instance=result,many=True)
          return  Response({'count':page_object.page.paginator.count,'result':ser.data})
    

    分页功能使用方式二

    DRF除了提供一个APIView还提供其它类供我们使用(分页功能一般和ListAPIView,CreateAPIView,....配合使用,APIView源码中没有调用分页功能)

    • settings.py
    ## DRF内置了分页功能,需要自己配置。
    # settings.py 全局配置,所有的DRF都可以使用
    REST_FRAMEWORK = { 
        "PAGE_SIZE":2, 
    }
    
    • view.py
    # ListAPIView
    # 继承它之后,它内部可以实现序列化和分页功能
    from rest_framework.pagination import PageNumberPagination
    class PageViewArticleView(ListAPIView):
        queryset = models.News.objects.all()
        filter_backends = [NewFilterBackend, ]
        serializer_class = NewSerializers
        # 自定义分页功能
        pagination_class = PageNumberPagination
          
    # 当请求来时,找get方法,自定义中没有去父类中找   
    class ListAPIView(mixins.ListModelMixin,GenericAPIView):
         def get(self, request, *args, **kwargs):
             # 执行list方法,先从自定义类寻找,没有的话就去父类寻找
            return self.list(request, *args, **kwargs)
    
    # 执行self.list方法,自定义没有从父类中寻找
    
    class ListModelMixin:
         def list(self, request, *args, **kwargs):
            # get_queryset取所有queryset,然后在执行filter_queryset筛选
            queryset = self.filter_queryset(self.get_queryset())
             '''
             class GenericAPIView(views.APIView):
                 def get_queryset(self):
                     # 取PageViewArticleView中寻找queryset
                     queryset = self.queryset
                     if isinstance(queryset, QuerySet):
                         queryset = queryset.all()
                     return queryset
             # 对queryset进行筛选        
             def filter_queryset(self, queryset):
                   # 先取filter_backends,从自定义类中寻找,方法需要自定义
                   for backend in list(self.filter_backends):
                      queryset = backend().filter_queryset(self.request, queryset, self)
                   return queryset
             '''
    
            page = self.paginate_queryset(queryset)
          '''
          class GenericAPIView(views.APIView):
          	def paginate_queryset(self, queryset):
                 # 如果def paginator(self) 返回一个None则跳过筛选    
        ——       if self.paginator is None: 
       |             return None
       			# 如果不为None,则执行PageNumberPagination对象.paginate_queryset
       |         return self.paginator.paginate_queryset(queryset, self.request, view=self)
       |  
       ——》  @property
             def paginator(self):
                 if not hasattr(self, '_paginator'):
                     # 如果自定义类中没定义pagination_class,那么_paginator = None
                     if self.pagination_class is None:
                         self._paginator = None
                     else:
                         self._paginator = self.pagination_class()
                 return self._paginator
          '''
            # 如果page不为None,执行序列化
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                '''
                   def get_serializer(self, *args, **kwargs):
                   	  # 从自定义类中获取serializer_class	
                        serializer_class = self.get_serializer_class()
                        kwargs['context'] = self.get_serializer_context()
                        return serializer_class(*args, **kwargs)
                        
                   def get_serializer_class(self):
                   	return self.serializer_class
                  
                '''
                return self.get_paginated_response(serializer.data)
             '''
             	def get_paginated_response(self, data):
             		assert self.paginator is not None
             		# 返回分页和数据信息
             		return self.paginator.get_paginated_response(data)
             '''
            # 如果page为None,直接序列化之后,返回给用户
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
      
    
    

    扩展

    使用PageNumberPagination分页时,除了把分页写在类中,还可以放在配置中

    ## DRF内置了分页功能,需要自己配置。
    # settings.py	全局配置:所有的DRF都可以使用
    REST_FRAMEWORK = { 
        "PAGE_SIZE":2, 
        "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination" 
    }
    
    class PageViewArticleView(ListAPIView): 
        queryset = models.Article.objects.all() 
        serializer_class = PageViewArticleSerializer 
       
       
    ## DRF内置了分页功能,需要自己配置。
    # 局部配置:当前类可用
    REST_FRAMEWORK = { 
        "PAGE_SIZE":2, 
    }
    
    class PageViewArticleView(ListAPIView): 
        queryset = models.Article.objects.all() 
        serializer_class = PageViewArticleSerializer 
        pagination_class = PageNumberPagination
    

    LimitOffffsetPagination

    # 这种不常用,建议使用上面PageNumberPagination
    from rest_framework.pagination import LimitOffsetPagination
    from rest_framework import serializers
    class PageArticleSerializer(serializers.ModelSerializer): 
    	class Meta:
        	model = models.Article 
        	fields = "__all__"
          
    class HulaLimitOffsetPagination(LimitOffsetPagination): 
    	# 每次最多展示几条数据
            max_limit = 2
       
    class PageArticleView(APIView): 
    	def get(self,request,*args,**kwargs): 
    		queryset = models.Article.objects.all()
    		page_object = HulaLimitOffsetPagination() 
    		result = page_object.paginate_queryset(queryset, request, self) 
    		ser = PageArticleSerializer(instance=result, many=True) 
    		return Response(ser.data)
    
    

    筛选

    这里我们先做个练习

    常规使用筛选

    model表

    class UserInfo(models.Model):
        """ 用户表 """
        username = models.CharField(verbose_name='用户名',max_length=32)
        password = models.CharField(verbose_name='密码',max_length=64)
    
    
    class Article(models.Model):
        """ 文章表 """
        category_choices = (
            (1,'咨询'),
            (2,'公司动态'),
            (3,'分享'),
            (4,'答疑'),
            (5,'其他'),
        )
        category = models.IntegerField(verbose_name='分类',choices=category_choices)
        title = models.CharField(verbose_name='标题',max_length=32)
        image = models.CharField(verbose_name='图片路径',max_length=128) # /media/upload/....
        summary = models.CharField(verbose_name='简介',max_length=255)
    
        comment_count = models.IntegerField(verbose_name='评论数',default=0)
        read_count = models.IntegerField(verbose_name='浏览数',default=0)
    
        author = models.ForeignKey(verbose_name='作者',to='UserInfo')
        date = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
    

    serializer

    class ArticleListSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Article
            fields = "__all__"
    

    views.py

    ---------正常使用---------
    from rest_framework.views import APIView
    from rest_framework.filters import BaseFilterBackend
    from rest_framework import serializers
    from rest_framework.pagination import PageNumberPagination
    from . import models
    # 筛选类
    class ArticleFilterBackend(BaseFilterBackend)
    	def filter_queryset(self,request,queryset,view)
        	val = request.query_params('cagetory')
            return queryset.filter(cagetory=val)
    
    
    class ArticleView(APIView):
         	""" 获取文章列表 """
            pk = kwargs.get('pk')
            # 全部数据
            if not pk:
                # 判断用户选择了哪个板块,并筛选出该板块的全部数据,返回给用户
                queryset = models.Article.objects.all()
                # 实例化筛选类对象
                obj = ArticleFilterBackend()
                
                # 执行筛选类中的filter_queryset进行序列化之后返回筛选值
                queryset = obj.filter_queryset(request,queryset,self)
                # 实例化分页对象
                pager = PageNumberPagination()
                # 将filter_queryset筛选之后的queryset分页,得到一个result结果
                result = pager.paginate_queryset(queryset,request,self)
                # 在将result进行序列化赋值给ser对象
                ser = ArticleListSerializer(instance=result,many=True)
    			  # 给前端返回分页后的数据
                return Response(ser.data)
            # 单条数据
            article_object = models.Article.objects.filter(id=pk).first()
            ser = PageArticleSerializer(instance=article_object,many=False)
            return Response(ser.data)
    

    上面的方法没有错,但是开发的时候很麻烦,DRF内部内置了筛选功能,供我们使用

    DRF内置筛选功能

    内置的筛选源码流程

    ---------使用内置筛选---------
    class ArticleView(APIView):
         	""" 获取文章列表 """
        queryset = models.News.objects.all()
        serializer_class = NewSerializers
        pagination_class = PageNumberPagination
        filter_backends = [ArticleFilterBackend, ]		###内置筛选功能
       
          
    # 请求来了之后走GET方法,自定义类中没有,找ListAPIView中的get方法
    class ListAPIView(mixins.ListModelMixin,
                      GenericAPIView):
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
       
    class ListModelMixin:
      	 # 执行ListModelMixin,
        def list(self, request, *args, **kwargs):
            # 先执行get_queryset,在执行filter_queryset筛选
            queryset = self.filter_queryset(self.get_queryset())
    		'''
             class GenericAPIView(views.APIView):
                 def get_queryset(self):
                     # 取PageViewArticleView中寻找queryset
                     queryset = self.queryset
                     if isinstance(queryset, QuerySet):
                         queryset = queryset.all()
                     return queryset
                     
             # 对queryset进行筛选        
             def filter_queryset(self, queryset):
             
                   # 先取filter_backends,从自定义类中寻找,筛选方法需要自定义
                   for backend in list(self.filter_backends):
                      queryset = backend().filter_queryset(self.request, queryset, self)
                   return 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)
    
  • 相关阅读:
    微服务-Nacos
    微服务RPC框架-Feign
    读书笔记之《大型分布式网站架构设计与实践》
    读书笔记之《Java并发编程的艺术》—— 四
    读书笔记之《Java并发编程的艺术》—— 三
    读书笔记之《Java并发编程的艺术》—— 二
    读书笔记之《Java并发编程的艺术》—— 一
    noip2021 训练4 做题记录
    noip 训练 (线段树专项)
    UVA11671 矩阵中的符号 Sign of Matrix 题解
  • 原文地址:https://www.cnblogs.com/zhuzhizheng/p/11918734.html
Copyright © 2011-2022 走看看