自定制过滤器 分页器(三种)如何使用(重点) 全局异常 封装Response对象 自动生成接口文档
一、自定制过滤器
基于django-filter扩写 1 写一个类MyFilter,继承BaseFilterVackend 2 重写filter_queryset方法,在该方法内部进行过滤 3 返回queryset对象(过滤后的queryset对象) 4 配置在视图类中 filter_backends = [MyFilter,]
class Myfilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
title =request.GET.get('title',None)
price =request.GET.get('price',None)
query = models.Book.objects.filter().all()
ll = []
if not (title or price):
return query
if title and price:
for i in query:
if i.title.startswith(title) and str(i.price).startswith(price):
ll.append(i)
elif title:
for i in query:
if i.title.startswith(title):
ll.append(i)
elif price:
for i in query:
if i.price.startswith(price):
ll.append(i)
return ll
二、分页器(三种)重点如何使用
1 内置了三种分页器 PafeNumberPagination:普通分页 LimitOffsetPagination:偏移分页 CursorPagination:游标分页 2 APIView和GenericAPIView+ListModelMixin 3 GenericAPIView+ListModelMixin的分页模式 4 PageNumberPagination:普通分页模式(用的最多) page_size = api_settings.PAGE_SIZE # 每页显示多少条 page_query_param = 'page' #查询参数 page_size_query_param = size #查询的时候指定每页显示多少条 max_page_size = 10 每页最多显示多少条 使用方式: 定义一个类,继承PageNumberPagination 重写四个属性 在继承 了GenericAPIView+ListModelMixin视图类中配置 pagination_class = MyPageNumberPagination 查询 http://127.0.0.1:8000/students/?page=1&size=5 5 LimitOffsetPagination: 偏移分页 default_limit = api_settings.PAGE_SIZE 默认条数 limit_query_param = 'limit' 查询时,指定查询多少条 offset_query_param = 'offset' 查询时,指定的起始位置是那 max_limit = None 查询时,最多返回多少条 使用方式:
定义一个类,继承LimitOffsetPagination
重写了四个属性
在继承了GenericAPIView+ListModelMixin视图类中配置
pagination_class = myPageNumberPagination
查询
http://127.0.0.1:8000/student/?limit=100&offset=1
6 CursorPagination:游标分页(速度快)
cursor_query_param = 'cursor' 查询的时候,指定的查询方式
page_size = api_settings.PAGE_SIZE 每页默认显示多少条
ordering = '-created' 排序方式
page_size_query_param = size 查询的时候指定每页显示多少条
max_page_size = None 每页最多显示多少条
使用方式:
定义一个类:
定义一个类,继承LimitOffsetPagination
重写四个属性
在继承了GenericAPIView+ListModelMixin视图类中配置
pagination_class = MyPageNumberPagination
查询
http://127.0.0.1:8000/students/
7 APIView的分页模式
新建一个类,继承普通分页,重写了四个属性
视图类写法如下
class StudentApiView(APIView):
def get(self,request):
student_list = Student.objects.all()
page=MyPageNumberPagination() 实例化得到对象
只需要换不同的分页类即可
res = page.paginate_queryset(student_list,request,self) #开始分页
ser = StudentSerializer(res,many=True)
return page.get_paginated_response(ser.data) 返回数据
from rest_framework.views import exception_handler
from rest_framework.response import Response
from .logger import log
from rest_framework import status
from django.db import DatabaseError
def common_exception_handel(exc,context):
log.error('view是:%s ,错误是%s'%(context['view'].__class__.__name__,str(exc)))
#context['view'] 是TextView的对象,想拿出这个对象对应的类
response = exception_handler(exc,context) #exception_handler类实例化的对象是一个response对象 # exc 报错的对象 if response is None: #如果reponse是None则说明出了异常 #错误信息记录日志 print(context,1111) #{'view': <app01.views.BookApiView object at 0x00000176FE5A2760>, # 'args': (), 'kwargs': {}, 'request': <rest_framework.request.Request: GET '/bookes/?page=4&s=2'>} 1111 print(context['view']) #那个视图函数出错 view = context['view'] #<app01.views.BookApiView object at 0x00000176FE5A2760>那个视图函数 request = context['request'] #<rest_framework.request.Request: GET '/bookes/?page=4&s=2'> 当次请求的request对象 print(context['request']) print(str(view)) print(request.path) #/bookes/请求的路径 print(request.method) #请求方式GET print(request.META.get('REMOTE_ADDR')) #127.0.0.1 ip地址 #记录日志(django日志) #sentry #print('执行函数出错,用户请求的地址是:%s,用户的ip是%s'% # (request.path, ['META']['REMOTE_ADDR']))
if instance(exc,DatabaseError): #判断错误这个属性(方法),是否属于DatabaseError这个类,如果是属于则返回这个报错。自己可以定义很多报错类型
return Response({'code':99,'detail':str(exc)},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response({'code':99,'detail':str(exc)},status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response sentry日志追踪异常 django写的 异步操作 可以使用于很多平台不管是用什么语言写的其本质是记录错误信息后, 调用一个sentry借口,通过网络将异常信息发送到sentry上即可。
简写
1 统一接口的返回方式,即便视图函数执行出错
2 使用方式
-写一个函数
def common_exception_handler(exc, context): #exc就是一个报错信息在APIvie中的dispacth,在执行完频率限制,认证,权限完只要出错就会执行
#except Exception as exc:
response = self.handle_exception(exc) #所以exc就是一个报错信息
log.error('view是:%s ,错误是%s'%(context['view'].__class__.__name__,str(exc)))
#context['view'] 是TextView的对象,想拿出这个对象对应的类名
response = exception_handler(exc, context)
if response is None:
response = Response({'code':999,'detail': '未知错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) #统一报错类型,不管出什么错都捕获,返回给前端这个,可以去日志中查看详细的错误类型
return response
-在setting中配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER':'app01.utils.common_exception_handler'
}
全局异常封装总结
运行exception_handle返回真正的response对象,如果出现异常,则response为None,全局异常 的捕获就是判断该Response是否为空。如果还可以根据exc的错误类型,来判断是数据库出了错误还是,其他错误。
#一般放在utils文件夹中
from rest_framework.response import Response
class APIResponse(Response):
#需要重写Response的__init__,用APIResponse接收参数,然后在调用父类的__init__,将参数传给父类 def __init__(self,code=100,msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs): dic = {'code':code,'msg':msg} if data: dic['data'] = data dic.update(kwargs) #字典中加入新的字典要用update不能用setdeafault
#需要调用父类的__init__,其本质还是运行了Response,只不过将传的参数进行了优化,更加方便。 super().__init__(data=dic,status=status, template_name=None,headers=headers, exception=False,content_type=content_type)
2 使用:
return APIResponse(code=100,msg='查询成功',data=ser.data,count=200,next='http://wwwa.asdfas')
自定义封装Response对象总结
第一步写一个类并继承(Response类)在类中
需要重写Response的__init__,用APIResponse接收参数,然后在调用父类的__init__,将参数传给父类。
1 借助于第三方:coreapi,swagger 2 在路由中 from rest_framework.documentation import include_docs_urls path('docs/', include_docs_urls(title='图书管理系统api')) 3 在配置文件中 REST_FRAMEWORK = { 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', } 4 写视图类(需要加注释) class BookListCreateView(ListCreateAPIView): """ get: 返回所有图书信息. asdfasfda post: 新建图书. """ queryset = Student.objects.all() serializer_class = StudentSerializer 5 只需要在浏览器输入,就可以看到自动生成的接口文档() http://127.0.0.1:8000/docs/