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)
posted @ 2019-11-23 18:46  犇羴鱻龘毳  阅读(441)  评论(0编辑  收藏  举报