回顾
1、编写登录接口,图书5大接口,实现图书5大接口匿名用户一分钟访问3次,登录用户一分钟访问10次
-方式一:
-写两个频率类(一个是根据IP限制,零以恶个是根据user id限制)
-方式2:
-使用内置的,如果可以,就没问题,如果有问题就要继续重写get_cache_key方法
2、一个接口即可以不登陆访问,又可以登录访问(匿名用户一分钟访问3次,登录用户一分钟访问10次)
-认证类:额外写
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
#写认证规则,如果认证通过,就正常return
#如果认证失败,抛异常
# 取出携带的随机字符串,去数据判断,如果有,正常登录,没有,告诉它没有登录
#token可以放在get请求的参数中,也可以放请求头中
token=request.GET.get('token')
res=models.UserToken.objects.filter(token=token).first()
if res:
return (res.user,token)
else:
return None # 由于是登录喝未登录都可以访问一个接口,所以未登录就返回个None,这样就不会报错,就正常走到下面的限制了
-未登录用户的频率限制
class MySimpleThrottleauth(SimpleRateThrottle):
scope = 'xxx'
def get_cache_key(self, request, view):
if not request.user.id: # 没有登录用户
return self.get_ident(request) # 根据ip限制
else:
return None # 登录用户则啥也不管,就会到下一个频率限制
-登录用户的频率限制,根据用户id限制
class MyLoginThrottle(SimpleRateThrottle):
scope = 'login'
def get_cache_key(self, request, view):
return request.user.pk
3、排序(内置排序规则)
-在视图类中配置
filter_backends =[OrderingFilter,]
ordering_fields=['id','age']
-查询:
http://127.0.0.1:8000/students/?ordering=-age
4、过滤(内置)
-在视图类中配置
filter_backends =[SearchFilter,]
search_fields=('name','age')
-查询:
http://127.0.0.1:8000/students/?search=9,l
5、过滤(django-filter)
-在视图类中配置
filter_backends =[DjangoFilterBackend,]
filter_fields=['name','age']
-查询:
http://127.0.0.1:8000/students/?name=lqz&age=10
#自定义过滤器
-查询所有才会有过滤---》list才需要过滤---》queryset = self.filter_queryset(self.get_queryset())---》GenericAPIView-->filter_queryset
#重写这个方法
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
基于django-filter扩写也可以,但是要熟悉它的源码
可以继承内置筛选器类来扩写
-1、写一个类MyFilter,继承BaseFilterBackend
-2、重写filter_queryset方法,在该方法内部进行过滤,(自己 设置的过滤条件)
-3、返回queryset对象(过滤后的queryset对象)
-4、配置在视图类中
filter_backends = [MyFilter,]
例子
#自定义过滤器,名字以l开头的人
from rest_framework.filters import BaseFilterBackend
class MyFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
#name=startswith_l 名字以l开头的人
value=request.GET.get('name')
first,last=value.split('_')
if first=='startswith':
queryset=queryset.filter(name__startswith=last)
return queryset
今日内容
1 分页器(三种)重点如何使用
-1、内置了三种分页器
-PageNumberPagination:普通分页器
-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/students/?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=MyCursorPagination()
# page=MyLimitOffsetPagination()
page=MyPageNumberPagination()# 实例化得到对象
# 只需要换不同的分页类即可
res=page.paginate_queryset(student_list,request,self)# 开始分页
ser=StudentSerializer(res,many=True) # 将分页好的数据传入序列化器
return page.get_paginated_response(ser.data) # 返回数据
2、全局异常
-1、统一接口的返回方式,以便视图函数执行出错
-2、使用方式
-写一个函数,可以把所有的异常都用一个异常信息捕获到返回给前端
def common_exception_handler(exc,context):
response=exception_handler(exc,context)
if response is None:
#错误日志记录日志
# , 'args': (), 'kwargs': {}, 'request': }
print(context['view']) # 哪个视图函数出错
view=context['view']
request=context['request']
print(context['request']) # 当此请求的request对象
print(str(view))
print(request.path)
print(request.method)
print(request.META.get('REMOTE_ADDR'))
#记录日志(django日志)
#sentry 这就是日志追踪的软件
print('执行视图函数出错,用户请求地址都是:%s,用户的IP是%s'%(request.path,request.META['REMOTE_ADDR']))
response=Response({'code':999,'dateil':str(exc)},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return response
-在setting中配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER':'app01.utils.common_exception_handler'
}
3、封装Response
-1、以后都使用自己封装的response
class APIResponse(Response):
def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None, **kwargs):# **kwargs用来接收其他的多余的传过来的参数,显示在前端
dic = {'code': code, 'msg': msg}
if data:
dic['data'] = data
dic.update(kwargs) # 这里使用update来更新字典
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')
# 返回的数据是自己封装的APIResponse里需要的参数,并且可以传入多余的自己想显示在前端的参数,都会被接收到
4、自动生成接口文档
-1、借助于第三方:coreapi,swagger
-2、在路由中
from rest_framework.documentation import include_docs_urls
path('docs/', include_docs_urls(title='图书管理系统api'))
其他的视图路由要配好,然后视图中要写详细的注释,用法。就会自动在docs路径下生成文档
-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/