首页 > 其他 > 详细

drf 其它组件分析

时间:2021-05-04 18:00:30      阅读:15      评论:0      收藏:0      [点我收藏+]

1.drf的权限组件

  进入drf的权限组件中,可以看到只要权限类中有has_permissions方法并且返回值是布尔值就可以实现全局或者局部的权限校验,他是在认证之后校验的

技术分享图片

 

 

 drf内部给我们提供了内置权限IsAdminUser,控制是否对网站后台有权限的人

  # 1 创建超级管理员
  # 2 写一个测试视图类
  from rest_framework.permissions import IsAdminUser
  from rest_framework.authentication import SessionAuthentication
  class TestView3(APIView):
    authentication_classes=[SessionAuthentication,]
    permission_classes = [IsAdminUser,]
    def get(self,request,*args,**kwargs):
    return Response(‘这是22222222测试数据,超级管理员可以看‘)
    # 3 超级用户登录到admin,再访问test3就有权限
    # 4 正常的话,普通管理员,没有权限看(判断的是is_staff字段)

2.频率/限流

  内置的频率限制:进入频率限制基类有这样几个类

  1) AnonRateThrottle

    限制所有匿名未认证用户,使用IP区分用户。

    使用DEFAULT_THROTTLE_RATES[‘anon‘] 来设置频次

  2)UserRateThrottle

    限制认证用户,使用User id 来区分。

    使用DEFAULT_THROTTLE_RATES[‘user‘] 来设置频次

  3)ScopedRateThrottle

    限制用户对于每个视图的访问频次,使用ip或user id。


 局部使用:

    from rest_framework.permissions import IsAdminUser
    from rest_framework.authentication import SessionAuthentication,BasicAuthentication
    from rest_framework.throttling import AnonRateThrottle
    class TestView5(APIView):
      authentication_classes=[]
      permission_classes = []
      throttle_classes = [AnonRateThrottle]
      def get(self,request,*args,**kwargs):
        return Response(‘我是未登录用户,TestView5‘)

全局配置中设置访问频率未登录用户1分钟访问5次,登录用户一分钟访问10次

‘DEFAULT_THROTTLE_RATES‘: {
‘anon‘: ‘3/minute‘,
‘user‘: ‘10/minute‘
}

自定义频率类

# 自定义的逻辑
#(1)取出访问者ip
#(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
#(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
#(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
#(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
class MyThrottles():
VISIT_RECORD = {}
def __init__(self):
self.history=None
def allow_request(self,request, view):
#(1)取出访问者ip
# print(request.META)
ip=request.META.get(‘REMOTE_ADDR‘)
import time
ctime=time.time()
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
if ip not in self.VISIT_RECORD:
self.VISIT_RECORD[ip]=[ctime,]
return True
self.history=self.VISIT_RECORD.get(ip)
# (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
while self.history and ctime-self.history[-1]>60:
self.history.pop()
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
if len(self.history)<3:
self.history.insert(0,ctime)
return True
else:
return False
def wait(self):
import time
ctime=time.time()
return 60-(ctime-self.history[-1])
全局使用:
REST_FRAMEWORK = {
‘DEFAULT_THROTTLE_CLASSES‘:[‘utils.MyThrottles‘,],
}
局部使用
 #在视图类里使用
throttle_classes = [MyThrottles,]

3过滤Filtering

对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。

  pip install django-filter

在配置文件中增加过滤后端的设置:

  

INSTALLED_APPS = [
...
‘django_filters‘, # 需要注册应用,
]

REST_FRAMEWORK = {
...
‘DEFAULT_FILTER_BACKENDS‘: (‘django_filters.rest_framework.DjangoFilterBackend‘,)
}

在视图中添加filter_fields属性,指定可以过滤的字段

class StudentListView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
filter_fields = (‘age‘, ‘sex‘)

# 127.0.0.1:8000/four/person/?sex=1


对于列表数据,REST framework提供了
OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序

4.排序

使用方法:

在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。

前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。

示例:

class PersonListView(ListAPIView):
queryset = Student.objects.all()
serializer_class = PersonModelSerializer
filter_backends = [OrderingFilter]
ordering_fields = (‘id‘, ‘age‘)

# 127.0.0.1:8000/person/?ordering=-age
# -id 表示针对id字段进行倒序排序
# id 表示针对id字段进行升序排序

如果需要在过滤以后再次进行排序,则需要两者结合!

from rest_framework.generics import ListAPIView
from person.models importPerson
from .serializers import PersonModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
class Student3ListView(ListAPIView):
queryset =Person.objects.all()
serializer_class =PersonModelSerializer
filter_fields = (‘age‘, ‘sex‘)
# 因为局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明,
# 否则过滤功能会失效
filter_backends = [OrderingFilter,DjangoFilterBackend]
ordering_fields = (‘id‘, ‘age‘)

5分页Pagination

REST framework提供了分页的支持。

我们可以在配置文件中设置全局的分页方式,如:

REST_FRAMEWORK = {
‘DEFAULT_PAGINATION_CLASS‘: ‘rest_framework.pagination.PageNumberPagination‘,
‘PAGE_SIZE‘: 100 # 每页数目
}

也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。

class LargeResultsSetPagination(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

注意:如果在视图内关闭分页功能,只需在视图内设置

  pagination_class = None 
1) 
PageNumberPagination可选分页器

前端访问网址形式:

GET  http://127.0.0.1:8000/Person/?page=4


page_size 每页数目可以在子类中定义的属性:

  • page_query_param 前端发送的页数关键字名,默认为”page”
  • page_size_query_param 前端发送的每页数目关键字名,默认为None
  • max_page_size 前端最多能设置的每页数量
# APIView
from rest_framework.pagination import PageNumberPagination
# 一 基本使用:url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size无效
class Pager(APIView):
def get(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)
# 二 自定制 url=http://127.0.0.1:8000/pager/?page=2&size=3
# size=30,无效,最多5条
class Mypage(PageNumberPagination):
page_size = 2
page_query_param = ‘page‘
# 定制传参
page_size_query_param = ‘size‘
# 最大一页的数据
max_page_size = 5
class Pager(APIView):
def get(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 Response(ser.data)
# 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
return page.get_paginated_response(ser.data)

#ListAPIView

# 声明分页的配置类
from rest_framework.pagination import PageNumberPagination
class StandardPageNumberPagination(PageNumberPagination):
# 默认每一页显示的数据量
page_size = 2
# 允许客户端通过get参数来控制每一页的数据量
page_size_query_param = "size"
max_page_size = 10
# 自定义页码的参数名
page_query_param = "p"

class StudentAPIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
pagination_class = StandardPageNumberPagination

# 127.0.0.1/four/students/?p=1&size=5

 2)LimitOffsetPagination
 前端访问网址形式:

  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
# APIView
# http://127.0.0.1:8000/pager/?offset=4&limit=3
from rest_framework.pagination import LimitOffsetPagination
# 也可以自定制,同简单分页
class Pager(APIView):
def get(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 page.get_paginated_response(ser.data)
return Response(ser.data)
#ListAPIView
from rest_framework.pagination import LimitOffsetPagination
class StandardLimitOffsetPagination(LimitOffsetPagination):
# 默认每一页查询的数据量,类似上面的page_size
default_limit = 2
limit_query_param = "size"
offset_query_param = "start"

class StudentAPIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
# 调用页码分页类
# pagination_class = StandardPageNumberPagination
# 调用查询偏移分页类
pagination_class = StandardLimitOffsetPagination



3)CursorPagination

前端访问网址形式:

GET http://127.0.0.1/four/students/?cursor=cD0xNQ%3D%3D

cursor_query_param:默认查询字段,不需要修改可以在子类中定义的属性:

  • page_size:每页数目
  • ordering:按什么排序,需要指定
#APIView
from rest_framework.pagination import CursorPagination
# 看源码,是通过sql查询,大于id和小于id
class Pager(APIView):
def get(self,request,*args,**kwargs):
# 获取所有数据
ret=models.Book.objects.all()
# 创建分页对象
page=CursorPagination()
page.ordering=‘nid‘
# 在数据库中获取分页的数据
page_list=page.paginate_queryset(ret,request,view=self)
# 对分页进行序列化
ser=BookSerializer1(instance=page_list,many=True)
# 可以避免页码被猜到
return page.get_paginated_response(ser.data)
# ListAPIView
class MyCursorPagination(CursorPagination):
page_size=2
ordering=‘-id‘
from rest_framework.generics import ListAPIView
class AuthorListView(ListAPIView):
serializer_class = serializers.AuthorModelSerializer
queryset = models.Author.objects.filter(is_delete=False)
pagination_class =MyCursorPagination

from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 2
page_query_param = ‘page‘
# 定制传参
page_size_query_param = ‘size‘
# 最大一页的数据
max_page_size = 5

class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2
# 最大一页的数据
max_limit = 5
class MyCursorPagination(CursorPagination):
page_size=2
ordering=‘-id‘
from rest_framework.generics import ListAPIView
class AuthorListView(ListAPIView):
serializer_class = serializers.AuthorModelSerializer
queryset = models.Author.objects.filter(is_delete=False)
pagination_class =MyCursorPagination

 

6.异常处理 Exceptions

应用

REST framework提供了异常处理,我们可以自定义异常处理函数。

1 使用方式

from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
# 先调用REST framework默认的异常处理方法获得标准错误响应对象
response = exception_handler(exc, context)

# 在此处补充自定义的异常处理
if response is None:
response.data[‘status_code‘] = response.status_code

return response

REST_FRAMEWORK = {
‘EXCEPTION_HANDLER‘: ‘my_project.my_app.utils.custom_exception_handler‘
}
 


如果未声明,会采用默认的方式,如下在配置文件中声明自定义的异常处理

rest_frame/settings.py

REST_FRAMEWORK = {
‘EXCEPTION_HANDLER‘: ‘rest_framework.views.exception_handler‘
}


补充上处理关于数据库的异常

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

# 在setting.py中配置
REST_FRAMEWORK = {
‘EXCEPTION_HANDLER‘: ‘app01.ser.exception_handler‘
}


APIException 所有异常的父类

REST framework定义的异常

  • ParseError 解析错误
  • AuthenticationFailed 认证失败
  • NotAuthenticated 尚未认证
  • PermissionDenied 权限决绝
  • NotFound 未找到
  • MethodNotAllowed 请求方式不支持
  • NotAcceptable 要获取的数据格式不支持
  • Throttled 超过限流次数
  • ValidationError 校验失败

也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。


 

drf 其它组件分析

原文:https://www.cnblogs.com/blackali/p/14729358.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!