前言
在本篇博客中,我们将详细解析Django REST framework中分页、过滤和搜索的定义、功能以及使用方法。我们不仅会介绍如何进行基本的设置和使用,还会深入探讨如何进行全局配置和局部配置,以满足不同场景下的需求。
分页功能 允许我们根据需求将数据划分为多个页面,确保用户在浏览大量数据时不会感到混乱或过载。过滤功能 则赋予了用户更精细地控制所看到数据的能力,通过预设条件或自定义查询,用户可以快速定位到所需信息。而搜索功能 则进一步增强了这种能力,让用户能够通过关键词迅速检索到相关数据。
一、分页
试想一下,为什么我们几乎不在网页中一次性展示请求获得的所有数据呢?
- 如果这个数据量相当小,比如只有几十条,那么一般情况下无需担心,一股脑渲染到页面中就行。
- 但如果这个数据量比较大,比如几百几千几万条,且一旦这种操作比较频繁,显然就会增加服务器负载,主要瓶颈是数据库。
这里不谈如何实现高并发,只谈如何以轻量化的方式获取并展示数据。
一种有效的方式就是实现分页查询:
将一次性获取所有数据的操作,分解为多次查询操作,每次操作只查询并展示一部分数据。其中每一次查询就是获取一页数据。
效果如下:
1. Django视图函数中实现分页
django视图函数中实现分页效果:
#views.py # 0.视图函数实现分页效果 def index(request): if request.method == 'POST': return JsonResponse({"message":"POST测试列表分页"}) # return HttpResponse('{"message":"Hello POST"}',content_type='application/json') elif request.method == 'GET': list1 = ["张三","李四","王五","赵六","立秋","李琦","离奇",64,84,84,6,54,5,6,7] # Paginator(列表数据,条数) pagtor = Paginator(list1,3) # 获取前端的查询参数:请求页数,页码 page = request.GET.get('page') print(page) data = pagtor.get_page(page) print(data.object_list) # return HttpResponse('{"message": data.object_list}',content_type='application/json') return JsonResponse({"message":"测试GET列表分页",'data': data.object_list})
注意:
JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs)
JsonResponse是HttpRespon的子类, 它主要和父类的区别在于:
- 它的默认
Content - Type
被设置为:application/json
- 第一个参数,
data
应该是一个字典类型, 当safe
这个参数被设置为: False, 那data可以填入任何能被转换为JSON格式的对象, 比如list, tuple, set.- 默认的
safe
参数是True,如果你传入的data数据类型不是字典类型, 那么它就会抛出TypeError的异常
2. DRF全局设置分页
注意:需要修改Django的全局配置文件
settings.py
# settings.py REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 3 #每页数据条数 }
#views.py class IndexView(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer
3. DRF局部设置分页
DRF自定义分页类对象并进行局部分页设置:
#views.py #导入分页器类 from rest_framework.pagination import PageNumberPagination # 局部分页配置 自定义分页器 class MyPaginator(PageNumberPagination): page_size = 2 # 每页数量 page_query_param = 'page' #查询参数:页码的参数名 page_size_query_param = 'page_size' #查询参数,每页数量的参数名 max_page_size = 10 #每页最大数量 # http://localhost:8000/app01/indexview/?page=1&page_size=10 # 1.DRF 分页 class IndexView(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer pagination_class = MyPaginator
4. 在APIView 中使用分页
前面的使用内置分页的视图函数都需要继承 GenericAPIView、ListModelMixin(或者直接继承ListAPIView),如果在正常的APIview中,如何实现自定义分页呢?
其实步骤是一样的,只不过APIView中没有提供数据和方法的封装,所有的操作,需要手动完成,下面我们可以自己编写继承 APIView 的视图函数实现分页。
class IndexView(APIView): def get(self,request): users = UserModel.objects.all() # 对数据集进行分页,自定义的分页器 # paginator = CommonPageNumberPagination() #加载系统分页器 paginator = PageNumberPagination() #局部设置,配置对应page_size大小和对应参数key paginator.page_size = 2 # 获取分页过后的数据 qs = paginator.paginate_queryset(users, request, self) # 对数据进行序列化,多条数据需要添加 many=True res = UserSer(qs, many=True) # 返回的方式一,只返回分页后的结果 # return Response(res.data) # 返回方式二,自己配置返回的其他信息,例如上一页下一页 # return Response({ # 'count': books.count(), # 'next': paginator.get_next_link(), # 'previous': paginator.get_previous_link(), # 'results': res.data # }) # 返回方式三,使用方法自动返回类似于方式二的内容 return paginator.get_paginated_response(res.data)
二、过滤
在 Django 中,
django-filter
是一个强大的第三方应用,它提供了一种简单、灵活且可定制的过滤器系统,允许开发者轻松地对 Django 查询集进行过滤和排序。过滤器 允许用户根据特定的条件来筛选数据。在 Django 中,这通常意味着对查询集(QuerySet)进行过滤。
1. django-filter的精准过滤
使用步骤
- 安装插件
该django-filter
库包含一个DjangoFilterBackend
类,该类支持针对REST框架的高度可自定义的字段筛选。
要使用
DjangoFilterBackend
,请先安装django-filter
pip install django-filter
- 注册APP
添加
'django_filters'
到Django的INSTALLED_APPS
:
#settings.py INSTALLED_APPS = [ ... 'django_filters', ... ]
- 配置过滤引擎
将过滤器后端添加到全局设置中:
REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] }
全局配置 精确过滤
import django_filters.rest_framework from rest_framework.generics import ListAPIView from app.models import StudentModel from app.serializer.studentSerializer import StudentSerializer # 1. 精确过滤 class IndexFilterViews(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer filterset_fields = ['name','gender'] # 过滤 # http://localhost:8000/app01/indexfilter/?name=张三 # http://localhost:8000/app01/indexfilter/?name=张三&gender=1
局部配置 精确过滤
import django_filters.rest_framework from rest_framework.generics import ListAPIView from app.models import StudentModel from app.serializer.studentSerializer import StudentSerializer # 局部配置 过滤 from django_filters.rest_framework import DjangoFilterBackend # 1. 精确过滤 class IndexFilterViews(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer filter_backends = [DjangoFilterBackend] filterset_fields = ['name','gender'] # 过滤 # http://localhost:8000/app01/indexfilter/?name=张三 # http://localhost:8000/app01/indexfilter/?name=张三&gender=1
2. django-filter的模糊过滤
默认的过滤器可以实现精准搜索功能,但是对于有些字段或者数据,在开发过程中需要实现模糊过滤,那么就需要进行过滤器的自定义实现,自定义一个高级过滤器,下面是 自定义过滤器
模糊过滤
# views_filter.py import django_filters.rest_framework from rest_framework.generics import ListAPIView from app.models import StudentModel from app.serializer.studentSerializer import StudentSerializer # 局部配置 过滤 from django_filters.rest_framework import DjangoFilterBackend # 过滤器 # 2. 模糊过滤 class StudentFilter(django_filters.rest_framework.FilterSet): """自定义过滤器类""" name = django_filters.CharFilter(field_name='name', lookup_expr='contains') # field_name 表示要过滤字段;lookup_expr 表示 过滤时要进行的操作, # contains 表示 包含,用来进行模糊过滤 maxgt_age = django_filters.NumberFilter(field_name='age', lookup_expr='gte') minlt_age = django_filters.NumberFilter(field_name='age', lookup_expr='lte') class Meta: model = StudentModel fields = ['name','maxgt_age','minlt_age'] #查询参数,与数据库无关 class StudentVagueFilter(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer filter_backends = [DjangoFilterBackend] # 局部配置 过滤 filterset_class = StudentFilter # 指明过滤器类 http://127.0.0.1:8000/app/students/?name=李
3. rest_framework的SearchFilter
rest_framework
的 SearchFilter
是 Django REST framework 提供的一个过滤器后端类,专门用于在 API 视图中执行文本搜索过滤。
SearchFilter
允许用户在查询字符串中通过特定的参数(默认为 search
)来搜索数据。这个过滤器基于数据库的全文搜索功能(如果可用),在指定的字段上执行全文搜索,并返回匹配指定搜索词的结果。
该搜索引擎依赖于
rest_framework
, 不需要安装额外的插件
- 配置搜索引擎
将过滤器后端添加到全局设置中:
REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.SearchFilter'] }
局部配置 / 全局配置 搜索:
from rest_framework.generics import ListAPIView from app.models import StudentModel from app.serializer.studentSerializer import StudentSerializer # 局部配置 搜索 #from rest_framework.filters import SearchFilter class IndexSearchView(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer # 局部配置 搜索 # filter_backends = [SearchFilter] search_fields = ['name'] # search_fields = ['^name'] 姓name的 # search_fields = ['=name'] 完全匹配,为name的 ordering_fields = ['age'] http://127.0.0.1:8000/app/index/?search=张三
PS:可以通过在字符前面添加各种字符来限制搜索行为
search_fields
:
'^'
开始搜索'='
完全匹配'$'
正则表达式搜索
三、排序
使用Ordering-Filter实现排序
将获取的数据按照一定的字段要求顺序进行排序,其实在model 模型类中也可以定义ordering 字段实现,排序实现其实还是用到了过滤部分的功能
实现排序要使用
DRF
提供的OrderingFilter
实现设置 过滤器后端(两种方式)
# 1.全局配置时--settings.py REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter'] } # 2.局部配置时---views_search.py # 导入 from rest_framework.filters import SearchFilter,OrderingFilter #视图 内部 (完整代码在下个代码块) filter_backends = [filters.OrderingFilter]
views_search.py 完整代码如下:
# views_search.py from rest_framework.generics import ListAPIView from app.models import StudentModel from app.serializer.studentSerializer import StudentSerializer # 局部配置(导包) 搜索 from rest_framework.filters import SearchFilter,OrderingFilter class IndexSearchView(ListAPIView): queryset = StudentModel.objects.all() serializer_class = StudentSerializer # 局部配置时要设置filter_backends ,全局配置过就不用了 # filter_backends = [SearchFilter] filter_backends = [SearchFilter,OrderingFilter] search_fields = ['name'] # search_fields = ['^name'] 以name开头的,姓 name的 # search_fields = ['=name'] 完全匹配,为 name的 ordering_fields = ['age'] http://127.0.0.1:8000/app/indexsearch/?ordering=-age # 从大到小 http://127.0.0.1:8000/app/indexsearch/?ordering=age # 从小到大