06-排序 分页 过滤

排序

查询多条和全部才会用到排序

  • 排序关键字:ordering

查询字符串

查询字符串(Query String)是指在 URL 中以问号(?)开始的部分,用于向服务器传递参数。它由一个或多个键值对组成,每个键值对之间用 & 符号分隔。

例如,在以下 URL 中,查询字符串是 ?page=2&category=books

在django种如何使用排序 ?ordering=price

-- 按价格升序
http://127.0.0.1:8000/books/?ordering=price  
select * from dd_book_spider dbs order by price asc;

-- 按价格降序 字段面前写一个-号
http://127.0.0.1:8000/books/?ordering=-price
select * from dd_book_spider dbs order by price desc;

-- 多个排序,用英文逗号隔开即可,一样支持 - 号从大到小排序
http://127.0.0.1:8000/books/?ordering=publish,-price

-- 出版社降序,价格也降序
http://127.0.0.1:8000/v1/publish/?ordering=-publish,-price

如何使用 必须是继承 GenericAPIView 的视图类才能使用

# 导入模块
from rest_framework.filters import OrderingFilter

class PublishView(GenericViewSet, ListModelMixin):
    # 固定写法
    filter_backends = [OrderingFilter]
    # 按哪一个字段取过滤,记不住取源码查看
    ordering_fields = ['price', "name", "publish"]
    
   

# 源码 serializer_class
def get_default_valid_fields(self, queryset, view, context={}):
	# ...
    serializer_class = getattr(view, 'serializer_class', None)

定制指定格式

如果纯自己写,不生效。

如果按照下面的格式,生效。

只要调用了self.get_queryset() 就会实现过滤

class PublishView(GenericViewSet, ListModelMixin):
	# ...
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset()) # 主要是这句话
        serializer = BookSerializer(instance=queryset, many=True)
        return Response({"code": 100, "msg": "成功", "results": serializer.data})

过滤

drf的过滤 (模糊匹配)

按照指定的条件取过滤

如何使用 ?searsh=publish

# 导入模块
from rest_framework.filters import SearchFilter

class PublishView(GenericViewSet, ListModelMixin):
    # 固定写法
    filter_backends = [SearchFilter]
    # 按哪一个字段取过滤,记不住取源码查看
    search_fields = ['price', "name", "publish"]

过滤和排序支持一起使用 ?serach=publish&ordering=price

from rest_framework.filters import OrderingFilter, SearchFilter


filter_backends = [SearchFilter, OrderingFilter]
search_fields = ["name"]
ordering_fields = ["price"]


# 按纪念排序
http://127.0.0.1:8000/v1/publish/?search=纪念
        
# 按纪念排序然后按价格降序
http://127.0.0.1:8000/v1/publish/?search=纪念&ordering=-price  
        
        
# ================= 控制字段进行模糊匹配
ordering_fields = ["publish", "name"]

# 只要书名或者出版社带 北 都能匹配
http://127.0.0.1:8000/v1/publish/?search=北 

第三方的过滤(支持精准匹配)django-filter

如何使用 直接使用查询字符串

# 安装模块
pip install django-filter

# 导入模块
from django_filters.rest_framework import DjangoFilterBackend

# 使用(一样需要继承GenericAPIView视图类 )
class PublishView(GenericViewSet, ListModelMixin):    
    queryset = DdBookSpider.objects.all()
    serializer_class = BookSpiderSerializer
    
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["price", "publish", "name"]
# 查询出版社为 九州出版社 并且价格为36的结果
http://127.0.0.1:8000/v1/publish/?publish=九州出版社&price=36

更多django-filter的用法:https://www.cnblogs.com/juelian/p/17560269.html

自定义过滤器(实现更高级的功能)

下面的这个写法就是

from rest_framework.filters import BaseFilterBackend
from django.db.models import Q


class CommonFilter(BaseFilterBackend):
    """
    request:表示客户端发送的 HTTP 请求,从而根据请求进行过滤操作。
    queryset:表示要进行过滤的查询集,通常是从数据库中获取的数据集合。
    view:  表示处理请求的视图类实例,即使用了自定义过滤器的视图类。
            通过 view 参数,可以访问视图类中定义的属性、方法等信息,以便根据视图的特定需求进行过滤操作。
    """
    def filter_queryset(self, request, queryset, view):
        name = request.query_params.get("name", None)
        price = request.query_params.get("price", None)   # --> 等同于 request.get("price")
        publish = request.query_params.get("publish", None)

        # queryset --> 视图层的 我这里是DdBookSpider.objects.all()
        # queryset 是可以一直 ... 查询的
        if name and price and publish:
            queryset = queryset.filter(Q(price=price) | Q(publish__contains=publish))
        
        if name:
            queryset = queryset.filter(name__contains=name)
        
        if price:
            queryset = queryset.filter(price=price)
            
        if publish:
            queryset = queryset.filter(publish__contains=publish)
            
        return queryset
    
# 视图层
from .filter import CommonFilter 

class PublishView(GenericViewSet, ListModelMixin):
    queryset = DdBookSpider.objects.all()
    serializer_class = BookSpiderSerializer
	
    # 写这个就可以了,不用写字段了
    filter_backends = [CommonFilter]

过滤和排序总结

  1. 必须继承 GenericAPIView
  2. 不论是自己写的过滤器,还是第三方的过滤器,都写在 filter_backends列表即可,会从左往右依次筛选
  3. 一般是过滤器+排序组合,而不是多个过滤器组合,因为每一个匹配规则都是不一样的
  4. 自定义的过滤器只需要写filter_backends就可以了,逻辑是我们后端自己取控制的

分页 (不建议重写list)

如果数据库的数据量很大,如果一次性把数据返回给前端肯定体验不好,也很消耗内存占用,这时候就使用到了分页。

  1. 使用了这个分页后,就可以放弃django默认的分页器了。
  2. 分页和过滤 排序 不冲突

分页的展现形式:

  1. web端:有页数
  2. 小程序等:上滑页面
from rest_framework.pagination import CursorPagination, PageNumberPagination, LimitOffsetPagination

方式1 基本分页 PageNumberPagination (推荐)

# 导入模块
from rest_framework.pagination import PageNumberPagination


# 写一个类 继承它
class CommonPagination(PageNumberPagination):
    # 定制几个类属性就可以了
    
    # n 每一页显示多少条,这里是10条 
    page_size = 10 
    
    
    # ?后面的查询参数 可以修改 前端指定数量会然后跳转到指定的页数
    # http://127.0.0.1:8000/v1/publish/?page=10
    page_query_param = 'page'

    # 每页最多显示几条
    # 比如下面 查询第10页每一页显示5条
    # http://127.0.0.1:8000/v1/publish/?page=10&size=5
    page_size_query_param = "size"
    
    
    # 控制size参数的最多条数 超过也是按照这个为准 比如定成了10 size为100 那么还是按10来
    max_page_size = 10


    # http://127.0.0.1:8000/v1/publish/?page=2&size=5  查询第2页 每页显示5条
    # http://127.0.0.1:8000/v1/publish/?page=6&size=599  查询第6页 每页显示10条
# 视图层
from .pagination import CommonPagination

class PublishView(GenericViewSet, ListModelMixin):
    queryset = DdBookSpider.objects.all()
    serializer_class = BookSpiderSerializer
    pagination_class = CommonPagination

image-20240417220849542

方式2 LimitOffsetPagination

from rest_framework.pagination import LimitOffsetPagination

class CommonLimitOffsetPagination(LimitOffsetPagination):
    # 每页显示几条 
    default_limit = 5 
    
    # 控制每页显示多少条
    # http://127.0.0.1:8000/v1/publish/?limit=5
    limit_query_param = 'limit'

    # 偏移量
    # http://127.0.0.1:8000/v1/publish/?offset=3 从第三条开始 取5条 (default_limit)
    # http://127.0.0.1:8000/v1/publish/?offset=4&limit=3  从第4条开始取3条 写了limit受limit控制
    offset_query_param = 'offset'
    
    # 每页最大的条数 写500也是10条
    max_limit = 10
# 视图层
from .pagination import CommonLimitOffsetPagination

# 限制超级管理员才可以访问
class PublishView(GenericViewSet, ListModelMixin):
    queryset = DdBookSpider.objects.all()
    serializer_class = BookSpiderSerializer
    pagination_class = CommonLimitOffsetPagination

image-20240417221712570

方式3 CursorPagination

  1. 必须先排序
  2. 页数不确定以及很多使用
# 分页
from rest_framework.pagination import CursorPagination

# 必须先排序  只能上一页或者下一页 不能直接跳转到某一页
# 在app端上使用的比较多,效率最高,数据量越大越明显 比如几十万条
class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor' # 查询条件 同上面的 limit page
    page_size = 10 # 每一页显示的条数
    ordering = 'id' # 按照什么去排序

image-20240417223607757

posted @ 2024-04-17 23:06  小满三岁啦  阅读(6)  评论(0编辑  收藏  举报