DRF之排序
内置排序
from rest_framework.generics import ListAPIView
from frequence.serializer import BookSerializer
from rest_framework.filters import OrderingFilter
from frequence.models import Book
class BookView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter] # 排序组件导入
ordering_fields = ("id", "price") # 可以使用id排序,也可以使用价格排序
DRF之过滤
内置过滤器
使用
from rest_framework.filters import SearchFilter
#继承了GenericAPIView的视图类,只要加入,两个类属性
class BookView(GenericViewSet, ListModelMixin):
serializer_class = BookSerializer
queryset = Book.objects.all()
filter_backends = [SearchFilter,]
search_fields=['name','price'] # 按name或price过滤,模糊查询
http://127.0.0.1:8000/api/v1/books?search=测试
第三方过滤器
pip3 install django-filter
在settings.py
里面注册app
INSTALLED_APPS = [
...
'rest_framework',
'django_filters',
]
使用
from django_filters.rest_framework import DjangoFilterBackend
class BookView(GenericViewSet, ListModelMixin):
serializer_class = BookSerializer
queryset = Book.objects.all()
filter_backends = [DjangoFilterBackend, ]
filter_fields = ['name', 'price']
http://127.0.0.1:8000/api/v1/books?name=测试&price=123
全局使用
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
局部使用
from django_filters.rest_framework import DjangoFilterBackend # 导入过滤组件
class BookAPI(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookModelSerializers
filter_backends = [DjangoFilterBackend, ] # 过滤组件导入
filter_fields = ("id","price") # 可以使用id过滤,也可以使用价格过滤
局部禁用
class BookAPI(ListAPIView):
filter_backends = [] # 设置为空
queryset = Book.objects.all()
serializer_class = BookModelSerializers
自定义过滤器
步骤
- 写一个类,继承
BaseFilterBackend
- 重写
filter_queryset
方法
使用
views.py
from .throttling import FilterName
class BookView(GenericViewSet, ListModelMixin):
serializer_class = BookSerializer
queryset = Book.objects.all()
filter_backends = [FilterName, ]
throttling
class FilterName(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
name = request.query_params.get('name')
price = request.query_params.get('price_gt')
if name and price:
return queryset.filter(name__contains=name, price__gt=price)
return queryset.filter()
DRF之分页
分页器 | 中文 | 介绍 |
---|---|---|
PageNumberPagination | 普通分页 | 非常常用 拥有上一页下一页 同时也可以做诸如1,2,3,4这样的跳转页数 |
LimitOffsetPagination | 偏移分页 | 相对使用较少 有一个基准点 可以根据这个基准点进行左偏移和右偏移 |
CursorPagination | 游标分页 | 效率最高,速度最快只有上一页和下一页 不可以做页数的跳转 |
- APIView:分页需要自己写
- GenericAPIView+ListModelMixin:直接用
基本分页
参数
参数 | 释义 |
---|---|
page_size = 3 | 每页显示的条数 |
page_query_param = ‘page’ | 查询的时候指定跳转到第几页 |
page_size_query_param = ‘size’ | 查询的时候指定每页显示的条数 |
max_page_size = 5 | 每页最大显示条数(相当于手动限制) |
使用
page.py
from rest_framework.pagination import PageNumberPagination
# 基本分页:正常的查第几页,每页显示多少条的方式
class CommonPageNumberPagination(PageNumberPagination):
#4个类属性
page_size = 2 #每页显示条数
page_query_param = 'page' # 查询页码参数 ?page=10
page_size_query_param = 'size' # ?page=3&size=5000
max_page_size = 5 # 可以通过size控制每页显示的条数,但是通过这个参数控制最多显示多少条
偏移分页
参数
参数 | 释义 |
---|---|
default_limit = 2 | 每页默认显示条数 |
limit_query_param = ‘limit’ | 查询时,指定显示几条 |
offset_query_param = ‘offset’ | (标杆)查询时,指定的起始位置是哪里 |
max_limit = 5 | 查询时,最多返回几条 |
使用
page.py
from rest_framework.pagination import LimitOffsetPagination
# 偏移分页
class CommonLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2 # 每页显示多少条
limit_query_param = 'limit' # 取多少条
offset_query_param = 'offset' #从第0个位置偏移多少开始取数据
max_limit = 5 # 最大限制条数
# offset=6&limit=90000
# http://127.0.0.1:8000/books/?limit=3&offset=3 # 从第三条开始取3条
# limit_query_description = _('Number of results to return per page.')
游标分页
参数
参数 | 释义 |
---|---|
page_size = 2 | 每页显示的条数 |
ordering = ‘pk’ | 排序字段(必填) |
cursor_query_param = ‘cursor’ | 每一页查询的key |
page_size_query_param = ‘size’ | 查询时,每一页显示几条 |
max_page_size | 查询时,最多返回几条 |
使用
page.py
# 游标分页针对于大数据量分页效率高---》可控性差--->只能选择上一页和下一页,不能直接跳转到某一个
class CommonCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 查询的名字 等同于 page=xx
page_size = 3 # 每页显示多少条
ordering = 'pk' # 排序规则,必须是表中有的字段,一般用id
# http://127.0.0.1:8000/books/?cursor=cD0z
view.py
pagination_class = MyPageNumberPagination
继承APIView实现分页
# APIView实现分页
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
class BookView(ViewSet):
def list(self,request):
books=Book.objects.all()
# 分页
# paginator=PageNumberPagination()
paginator=CommonLimitOffsetPagination()
#分页过后的数据
qs=paginator.paginate_queryset(books,request,self)
#序列化
ser=BookSerializer(qs,many=True)
# 第一种方式:每页总条数,上一页,下一页
# return Response(ser.data)
# 第二种:自己凑
# return Response({
# 'count':books.count(),
# 'next': paginator.get_next_link(),
# 'previous':paginator.get_previous_link(),
# 'results': ser.data
# })
# 第三种;直接使用分页类的方法
return paginator.get_paginated_response(ser.data)
DRF之异常处理
自定义全局异常
utils.py
# 第一步:写一个函数
from rest_framework.views import exception_handler
from rest_framework.response import Response
def common_exception_handler(exc, context):
# 正常来讲,在这里需要记录日志
print(context['view']) # 视图类的对象
print(context['request']) #当前请求的对象----》ip,用户id,当前时间,请求地址来
view=context['view']
request=context['request']
print('ip地址为:%s的用户,访问:%s 视图类,报错了,请求地址是:%s'%(request.META.get('REMOTE_ADDR'),str(view),request.path))
response=exception_handler(exc, context)
if response: # 这是drf的异常,其实人家已经处理了,但是不符合我的格式 {code:999,msg:错误}
res=Response({'code':999,'msg':response.data.get('detail')})
else:
# res=Response({'code':998,'msg':'服务器错误,请联系系统管理员'})
res=Response({'code':998,'msg':str(exc)})
settings.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER':'frequence.utils.capture_exception'
}