from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.filters import SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
from . import models, serializers
# 搜索课程接口
class SearchCourseViewSet(GenericViewSet, ListModelMixin):
queryset = models.Course.objects.filter(is_delete=False, is_show=True).all()
serializer_class = serializers.CourseSerializer
# pagination_class = pagination.PageNumberPagination
# filter_backends = [DjangoFilterBackend]
# filter_fields = ['name']
filter_backends = [SearchFilter]
search_fields = ['name','id']
filter_fields = ['name'] 精确查询 用自定义区间过滤类可查询自定义字段
search_fields = ['name','id'] 模糊查询 可查询多个字段
区间过滤
自定义区间过滤类
from django_filters.filterset import FilterSet
from . import models
from django_filters import filters
class CourseFilterSet(FilterSet):
# 区间过滤:field_name关联的Model字段;lookup_expr设置规则;gt是大于,gte是大于等于;
min_price = filters.NumberFilter(field_name='price', lookup_expr='gte')
max_price = filters.NumberFilter(field_name='price', lookup_expr='lte')
class Meta:
model = models.Course
# 如果过滤条件仅仅就是Model已有的字段,方式一更好
# 但是方式二可以自定义过滤字段
fields = ['course_category', 'min_price', 'max_price']
视图里配置
filter_class = CourseFilterSet
一 过滤Filtering
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
1
|
pip install django-filter
|
在配置文件中增加过滤后端的设置:
1 2 3 4 5 6 7 8 9
|
INSTALLED_APPS = [ ... 'django_filters', ]
REST_FRAMEWORK = { ... 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
|
在视图中添加filter_fields属性,指定可以过滤的字段
1 2 3 4 5 6
|
classStudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer filter_fields = ('age', 'sex')
|
二 排序
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
示例:
1 2 3 4 5 6 7 8 9
|
classStudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_backends = [OrderingFilter] ordering_fields = ('id', 'age')
|
如果需要在过滤以后再次进行排序,则需要两者结合!
1 2 3 4 5 6 7 8 9 10 11 12
|
from rest_framework.generics import ListAPIView from students.models import Student from .serializers import StudentModelSerializer from django_filters.rest_framework import DjangoFilterBackend class Student3ListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_fields = ('age', 'sex')
|
REST framework提供了分页的支持。
我们可以在配置文件中设置全局的分页方式,如:
1 2 3 4
|
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 }
|
也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas
属性来指明。
1 2 3 4 5 6 7 8
|
classLargeResultsSetPagination(PageNumberPagination): page_size = 1000 page_size_query_param = 'page_size' max_page_size = 10000 class BookDetailView(RetrieveAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer pagination_class = LargeResultsSetPagination
|
注意:如果在视图内关闭分页功能,只需在视图内设置
1
|
pagination_class = None
|
可选分页器
1) PageNumberPagination
前端访问网址形式:
可以在子类中定义的属性:
- page_size 每页数目
- page_query_param 前端发送的页数关键字名,默认为”page”
- page_size_query_param 前端发送的每页数目关键字名,默认为None
- max_page_size 前端最多能设置的每页数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
from rest_framework.pagination import PageNumberPagination
classPager(APIView): defget(self,request,*args,**kwargs):
ret=models.Book.objects.all()
page=PageNumberPagination()
page_list=page.paginate_queryset(ret,request,view=self)
ser=BookSerializer1(instance=page_list,many=True) return Response(ser.data)
classMypage(PageNumberPagination): page_size = 2 page_query_param = 'page'
page_size_query_param = 'size'
max_page_size = 5 classPager(APIView): defget(self,request,*args,**kwargs):
ret=models.Book.objects.all()
page=Mypage()
page_list=page.paginate_queryset(ret,request,view=self)
ser=BookSerializer1(instance=page_list,many=True)
return page.get_paginated_response(ser.data)
from rest_framework.pagination import PageNumberPagination classStandardPageNumberPagination(PageNumberPagination):
page_size = 2
page_size_query_param = "size" max_page_size = 10
page_query_param = "p"
classStudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer pagination_class = StandardPageNumberPagination
|
2)LimitOffsetPagination
前端访问网址形式:
1
|
GET http://127.0.0.1/four/students/?limit=100&offset=400
|
可以在子类中定义的属性:
- default_limit 默认限制,默认值与
PAGE_SIZE
设置一直
- limit_query_param limit参数名,默认’limit’
- offset_query_param offset参数名,默认’offset’
- max_limit 最大limit限制,默认None
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
from rest_framework.pagination import LimitOffsetPagination
classPager(APIView): defget(self,request,*args,**kwargs):
ret=models.Book.objects.all()
page=LimitOffsetPagination()
page_list=page.paginate_queryset(ret,request,view=self)
ser=BookSerializer1(instance=page_list,many=True)
return Response(ser.data)
from rest_framework.pagination import LimitOffsetPagination classStandardLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2 limit_query_param = "size" offset_query_param = "start"
classStudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer
pagination_class = StandardLimitOffsetPagination
|
3)CursorPagination
前端访问网址形式:
1
|
GET http://127.0.0.1/four/students/?cursor=cD0xNQ%3D%3D
|
可以在子类中定义的属性:
- cursor_query_param:默认查询字段,不需要修改
- page_size:每页数目
- ordering:按什么排序,需要指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
from rest_framework.pagination import CursorPagination
|
应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination class MyPageNumberPagination(PageNumberPagination): page_size = 2 page_query_param = 'page'
|
四 异常处理 Exceptions
REST framework提供了异常处理,我们可以自定义异常处理函数。
4.1 使用方式
1 2 3 4 5 6 7 8 9 10 11
|
from rest_framework.views import exception_handler
defcustom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response isNone: response.data['status_code'] = response.status_code
return response
|
在配置文件中声明自定义的异常处理
1 2 3
|
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' }
|
如果未声明,会采用默认的方式,如下
rest_frame/settings.py
1 2 3
|
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler' }
|
4.2 案例
补充上处理关于数据库的异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
from rest_framework.views import exception_handler from rest_framework.response import Response from rest_framework.views import exception_handler as drf_exception_handler from rest_framework import status from django.db import DatabaseError
def exception_handler(exc, context): response = drf_exception_handler(exc, context)
if response is None: view = context['view'] print('[%s]: %s' % (view, exc)) if isinstance(exc, DatabaseError): response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) else: response = Response({'detail': '未知错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return response
|
自定义异常
from rest_framework.views import exception_handler
def My_error(exc,context): # exc 异常对象 context 异常函数
responce = exception_handler(exc,context) # 1.返回NONE(drf未处理) 2.处理了(不是期望的要求)
if not responce:
return Response({'code':‘401’,'msg':str(exc)})
else:
return Response({'code':‘401’,'msg':responce.data.get("detail")})
4.3 REST framework定义的异常
- APIException 所有异常的父类
- ParseError 解析错误
- AuthenticationFailed 认证失败
- NotAuthenticated 尚未认证
- PermissionDenied 权限决绝
- NotFound 未找到
- MethodNotAllowed 请求方式不支持
- NotAcceptable 要获取的数据格式不支持
- Throttled 超过限流次数
- ValidationError 校验失败
也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。