18 过滤排序分页异常处理
# 只针对于查询所有接口 # 127.0.0.1:8000/four/students/?sex=1
-内置过滤类SearchFilter,配置search_fields,指定过滤的字段,可以模糊匹配,?search=搜索条件
-自定义过滤类:写一个类,继承BaseFilterBackend,重写filter_queryset方法,方法返回qs对象,就是过滤后的对象,配置在视图类中即可
-django-filter,导入DjangoFilterBackend,配置在视图类上,配置filter_fields=['name','publish'],指定过滤字段,不能模糊匹配,?name=搜索条件
#models.py from django.db import models class Book(models.Model): name=models.CharField(max_length=32) price=models.IntegerField() publish=models.CharField(max_length=32) #serializers.py from rest_framework import serializers from app01.models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model=Book fields="__all__" #views.py from django.shortcuts import render from rest_framework.generics import GenericAPIView,ListAPIView from rest_framework.mixins import ListModelMixin from rest_framework.viewsets import ViewSetMixin,GenericViewSet from app01.models import Book from app01.serializer import BookSerializer from rest_framework.response import Response from rest_framework.filters import SearchFilter #class BookView(ViewSetMixin,GenericAPIView,ListModelMixin): #BookView三种写法 #class BookView(GenericViewSet,ListModelMixin): class BookView(ViewSetMixin,ListAPIView): queryset = Book.objects.all() serializer_class = BookSerializer # 方式一:笨办法 def list(self, request, *args, **kwargs): query=request.GET.get('name') qs=self.get_queryset().filter(name=query) ser=self.get_serializer(instance=qs,many=True) return Response(ser.data) # 方式二:使用内置的过滤类(可以自己写,使用第三方) filter_backends=[SearchFilter,] ## 过滤类:可以自己写,也可以用内置,使用第三方(filter_backends在ListAPIView的GenericAPIView中找)
# SearchFilter类中通过反射获取的字段
search_fields=['name','publish'] # 按那个字段过滤,可以模糊匹配
# http://127.0.0.1:8000/book/?search=条件 并且支持模糊匹配
#urls.py
from django.contrib import admin
from django.urls import path
from app01.views import BookView
from rest_framework.routers import SimpleRouter
router=SimpleRouter()
router.register('book',BookView,'book')
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls
#settings.py需要注册'rest_framework',
2.排序
内置排序类OrderingFilter,配置ordering_fields,指定排序的字段,可以实现排序,?ordering=-price
# class BookView(ViewSetMixin, ListAPIView): # queryset = Book.objects.all() # serializer_class = BookSerializer # # ### 方法一:笨办法 # # def list(self, request, *args, **kwargs): # # query=request.query_params.get('ordering') # # qs = self.get_queryset() # # if query: # # qs=qs.order_by(query) # # ser=self.get_serializer(instance=qs,many=True) # # return Response(ser.data) # # ### 方式二: # filter_backends = [OrderingFilter] # 内置的排序类 # ordering_fields=['price'] # # http://127.0.0.1:8000/book/?ordering=price #升序 # # http://127.0.0.1:8000/book/?ordering=-price #降序
3.过滤排序连用(尽量把过滤写在前面)
### 排序过滤连用 # class BookView(ViewSetMixin, ListAPIView): # queryset = Book.objects.all() # serializer_class = BookSerializer # # ### 方式: # filter_backends = [SearchFilter,OrderingFilter] # 放在第一位的,最好能优先过滤掉很多数据 # ordering_fields=['price'] # search_fields = ['publish'] # http://127.0.0.1:8000/book/?search=出版社&ordering=price
# 第一步,写一个类,继承基类BaseFilterBackend,重写某个方法filter_queryset,返回的数据就是过滤后的qs对象
# 配置一下,在视图类中配置
filter_backends = [FilterByName]
### 过滤类filters.py from rest_framework.filters import BaseFilterBackend class FilterByName(BaseFilterBackend): def filter_queryset(self, request, queryset, view): #http://127.0.0.1:8000/book/?name=红楼梦 query=request.query_params.get('name') if query: return queryset.filter(name__contains= query ) else: return queryset return queryset ### 视图类views.py # from .filters import FilterByName # class BookView(ViewSetMixin, ListAPIView): # queryset = Book.objects.all() # serializer_class = BookSerializer # filter_backends = [FilterByName]
## 使用第三方:django-filter,需要安装 pip3 install django-filter
# 是一个app,在项目中注册
# 导入django-filter提供的过滤类
#views.py
from django_filters.rest_framework import DjangoFilterBackend class BookView(ViewSetMixin, ListAPIView): queryset = Book.objects.all() serializer_class = BookSerializer filter_backends = [DjangoFilterBackend,] filter_fields=['name','publish'] # 不支持模糊匹配,只支持精准匹配,多个搜索条件是and,如果要用or,需要使用多表查询的Q查询
#settings.py
注册'django_filters',
PageNumberPagination:用的多,传统的分页 page=第几页&size=每页多少条
LimitOffsetPagination:从第几条开始offset=第几条,取几条limit=取几条
CursorPagination:只能选择看上一页或下一页,效率高
重写某个分页类,修改某几个类属性后,把分页类,配置在视图类上:pagination_class=分页类
# 三种分页方式,需要重写类属性 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination class MyPageNumberPagination(PageNumberPagination): page_size = 2 # 每页显示的条数 page_query_param = 'p' #http://127.0.0.1:8000/book/?page=3 page_size_query_param = 's' # 每页显示多少条 max_page_size = 3 # 每页最大显示3条 class MyLimitOffsetPagination(LimitOffsetPagination): default_limit = 1 # 每页显示的条数 limit_query_param = 'limit' # 取几条 offset_query_param = 'offset' # 标杆,从第几个位置开始取 默认情况,每页显示一条 max_limit = 5 # 最大每页显示多少条 # 分页速度快,有缺陷,只能上一页和下一页,不能直接跳到某一页,针对于数据量大,可以使用该分页方式 class MyCursorPagination(CursorPagination): cursor_query_param = 'cursor' # 不用动,没有用 page_size = 3 # 每页显示多少条 ordering = 'id' # 游标分页的原理,是先排序,然后使用游标标志位置,只能往前,往后,所以只能上一页和下一页
#### 在视图类中使用views.py
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
from .pagination import MyPageNumberPagination as PageNumberPagination
from .pagination import MyLimitOffsetPagination as LimitOffsetPagination
from .pagination import MyCursorPagination as CursorPagination
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 带分页功能
#pagination_class =PageNumberPagination
#pagination_class =LimitOffsetPagination
pagination_class = CursorPagination # 配置成你重写的类,局部配置
# 全局使用
#settings.py REST_FRAMEWORK={'DEFAULT_PAGINATION_CLASS': None,}
基于APIview实现分页: