本文主要是介绍【django2.0之Rest_Framework框架三】rest_framework认证,权限,限流,过滤,排序,分页,异常处理,生成文档介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. 认证Authentication
- 全局配置
可以在配置文件中配置全局默认的认证方案。
from rest_framework import settings# 在settings配置文件中,我们可以进行下面的配置来覆盖默认配置
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': (#哪个写在前面,优先使用哪个认证'rest_framework.authentication.SessionAuthentication', # session认证,admin后台其实就使用的session认证,其实接口开发很少用到session认证,所以我们通过配置可以改为其他认证,比如后面项目里面我们用到jwt,JSON WEB TOKEN认证,或者一些配合redis的认证'rest_framework.authentication.BasicAuthentication', # 基本认证,工作当中可能一些测试人员会参与的话,他们会将一些认证数据保存在内存当中,然后验证的,我们基本上用不上)
}
- 局部使用
也可以在每个视图中通过设置authentication_classess
属性来设置,比如说我们很多接口的数据都是可以让别人获取数据的,但是有可能有些接口是调用给别人网站的,有可能到时候我们就需要一些单独的认证了
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIViewclass ExampleView(APIView):# 类属性authentication_classes = [SessionAuthentication, BasicAuthentication] #也可以写成元祖形式的,到时候我们使用我们自己开发的认证组件的时候,就需要自己写一个认证组件类,然后写在列表中来使用...
认证失败会有两种可能的返回值:
- 401 Unauthorized 未认证
- 403 Permission Denied 权限被禁止
自定义认证组件
## 写一个认证类 students/utils/app_auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from students.models import UserToken
class MyAuthentication(BaseAuthentication):def authenticate(self, request):# 认证逻辑,如果认证通过,返回两个值#如果认证失败,抛出AuthenticationFailed异常token=request.GET.get('token')if token:user_token=UserToken.objects.filter(token=token).first()# 认证通过if user_token:return user_token.user,tokenelse:raise AuthenticationFailed('认证失败')else:raise AuthenticationFailed('请求地址中需要携带token')# 可以有多个认证,从左到右依次执行
# 全局使用,在setting.py中配置
REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["students.utils.app_auth.MyAuthentication",]
}
# 局部使用,在视图类上写
## views.py
from students.utils.app_auth import MyAuthentication
class StudentView(APIView):authentication_classes = [MyAuthentication, ]def get(self,request):print(request.user) # 用户名print(request.auth) # tokenreturn Response({'msg':'ok'})
# 局部禁用
authentication_classes=[]
2. 权限Permissions
权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。
- 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
- 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断
- 全局使用
可以在配置文件中全局设置默认的权限管理类,如
REST_FRAMEWORK = {....'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated', #登录状态下才能访问我们的接口,可以通过退出admin后台之后,你看一下还能不能访问我们正常的接口就看到效果了)
}
如果未指明,则采用如下默认配置
from rest_framework import permissions
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny', #表示任何人都可以进行任何的操作,没做限制
)
- 局部使用
也可以在具体的视图中通过permission_classes
属性来设置,如
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIViewclass ExampleView(APIView):permission_classes = (IsAuthenticated,)...
内置提供的权限
AllowAny
允许所有用户IsAuthenticated
仅通过认证的用户
自定义权限的使用
如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并重写has_permission(self, request, view)
方法表示是否可以访问视图, view表示当前视图对象。如果权限通过,就返回True,不通过就返回False
## utils/permissions.py
from rest_framework.permissions import BasePermissionclass UserPermission(BasePermission):def has_permission(self, request, view):# 不是超级用户,不能访问# 由于认证已经过了,request内就有user对象了,当前登录用户user=request.user # 当前登录用户# 如果该字段用了choice,通过get_字段名_display()就能取出choice后面的中文print(user.get_user_type_display())if user.user_type==1:return Trueelse:return False# 局部使用
## views.py
class TestView(APIView):permission_classes = [permissions.UserPermission]def get(self,request):return Response({'msg':'ok'})
# 全局使用
REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",],'DEFAULT_PERMISSION_CLASSES': ['app01.app_auth.UserPermission',],
}
# 局部禁用
class TestView(APIView):permission_classes = []
3. 限流Throttling
可以对接口访问的频次进行限制,以减轻服务器压力。
一般用于付费购买次数,投票等场景使用.
- 全局使用
可以在配置文件中,使用DEFAULT_THROTTLE_CLASSES
和DEFAULT_THROTTLE_RATES
进行全局配置
REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ('rest_framework.throttling.AnonRateThrottle', # 匿名用户,未登录的'rest_framework.throttling.UserRateThrottle' # 经过登录之后的用户),'DEFAULT_THROTTLE_RATES': {'anon': '100/day','user': '1000/day'}
}
DEFAULT_THROTTLE_RATES
可以使用 second
, minute
, hour
或day
来指明周期。
源码:
{'s': 1, 'm': 60, 'h': 3600, 'd': 86400} m表示分钟,可以写m,也可以写minute
- 局部使用
也可以在具体视图中通过throttle_classess
属性来配置
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIViewclass ExampleView(APIView):throttle_classes = (UserRateThrottle,)...
内置频率组件源码
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
import time
from rest_framework import exceptions
visit_record = {}
class VisitThrottle(BaseThrottle):# 限制访问时间VISIT_TIME = 10VISIT_COUNT = 3# 定义方法 方法名和参数不能变def allow_request(self, request, view):# 获取登录主机的idid = request.META.get('REMOTE_ADDR')self.now = time.time()if id not in visit_record:visit_record[id] = []self.history = visit_record[id]# 限制访问时间while self.history and self.now - self.history[-1] > self.VISIT_TIME:self.history.pop()# 此时 history中只保存了最近10秒钟的访问记录if len(self.history) >= self.VISIT_COUNT:return Falseelse:self.history.insert(0, self.now)return Truedef wait(self):return self.history[-1] + self.VISIT_TIME - self.now
可选限流类
1) AnonRateThrottle
限制所有匿名未认证用户,使用IP区分用户。
使用DEFAULT_THROTTLE_RATES['anon']
来设置频次
2)UserRateThrottle
限制认证用户,使用User id 来区分。
使用DEFAULT_THROTTLE_RATES['user']
来设置频次
示例
全局配置中设置访问频率
'DEFAULT_THROTTLE_CLASSES': ('rest_framework.throttling.AnonRateThrottle','rest_framework.throttling.UserRateThrottle'),'DEFAULT_THROTTLE_RATES': {'anon': '3/m','user': '10/m'}
4. 过滤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 = StudentSerializerfilter_fields = ('age', 'sex') # 配置可以按照哪个字段来过滤# 127.0.0.1:8000/stu/students/?sex=1
5. 排序Ordering
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends
,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering
参数,如果包含了ordering
参数,则按照ordering
参数指明的排序字段对数据集进行排序。
前端可以传递的ordering
参数的可选字段值需要在ordering_fields
中指明。
示例:
from rest_framework.filters import OrderingFilter
class Students7View(ModelViewSet):queryset = models.Student.objects.all() # 必须写这个参数 ,方法中使用的self.get_queryset()方法自动获取到queryset属性数据serializer_class = StudentModelSerializer # 非必填属性,self.get_serializer获取到serializer_class制定的序列化器类filter_backends = (OrderingFilter,)ordering_fields = ('id', 'age')# students/?ordering=-id# 127.0.0.1:8000/books/?ordering=-age
# 必须是ordering=某个值
# -id 表示针对id字段进行倒序排序
# id 表示针对id字段进行升序排序
如果需要在过滤以后再次进行排序,则需要两者结合!
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 = StudentModelSerializerfilter_fields = ('age', 'sex')# 因为filter_backends是局部过滤配置,局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明,# 否则过滤功能会失效filter_backends = [OrderingFilter,DjangoFilterBackend]ordering_fields = ('id', 'age')# 127.0.0.1:8000/books/?sex=1&ordering=-age
6. 分页Pagination
REST framework提供了分页的支持。
我们可以在配置文件中设置全局的分页方式,如:
REST_FRAMEWORK = {# 全局分页,一旦设置了全局分页,那么我们drf中的视图扩展类里面的list方法提供的列表页都会产生分页的效果。所以一般不用全局分页'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 100 # 每页最大数据量
}
也可通过自定义Pagination
类,来为视图添加不同分页行为。在视图中通过pagination_class
属性来指明。
class LargeResultsSetPagination(PageNumberPagination):page_size = 1000#127.0.0.1:8001/students/?page=5&page_size=10page_size_query_param = 'page_size'max_page_size = 10000
class BookDetailView(RetrieveAPIView):queryset = BookInfo.objects.all()serializer_class = BookInfoSerializerpagination_class = LargeResultsSetPagination# pagination_class = None
注意:如果在视图内关闭分页功能,只需在视图内设置
pagination_class = None
可选分页器
1) PageNumberPagination
前端访问地址形式:
GET http://127.0.0.1:8000/students/?page=4
可以在子类中定义的属性:
page_size
每页数目page_query_param
前端发送的页数关键字名,默认为"page"
page_size_query_param
前端发送的每页数目关键字名,默认为None
max_page_size
前端最多能设置的每页数量
# 声明分页的配置类
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 = StudentModelSerializerpagination_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 #从下标为400的记录开始,取100条记录
可以在子类中定义的属性:
default_limit
默认限制,每页数据量大小,默认值与PAGE_SIZE
设置一致limit_query_param
limit参数名,默认'limit'
, 可以通过这个参数来改名字offset_query_param
offset参数名,默认'offset'
,可以通过这个参数来改名字max_limit
最大limit限制,默认None
, 无限制
from rest_framework.pagination import LimitOffsetPagination
class StandardLimitOffsetPagination(LimitOffsetPagination):# 默认每一页查询的数据量,类似上面的page_sizedefault_limit = 2limit_query_param = "size"offset_query_param = "start"class StudentAPIView(ListAPIView):queryset = Student.objects.all()serializer_class = StudentModelSerializer# 调用页码分页类# pagination_class = StandardPageNumberPagination# 调用查询偏移分页类pagination_class = StandardLimitOffsetPagination
7. 异常处理 Exceptions
看一个简单的示例
class APIError(Exception):passclass Student2APIView(APIView):def get(self,request,pk):try:instance = Student.objects.get(pk=pk)except Student.DoesNotExist:raise APIError('自定义API错误')return Response({"message":"访问的商品已经下架~"})serializer = StudentModelSerializer(instance=instance)return Response(serializer.data)
REST framework提供了异常处理,我们可以自定义异常处理函数。
可以创建一个utils
文件夹,里面放一个exceptions.py
文件,名字随便写,然后写下面的内容
from rest_framework.views import exception_handlerdef custom_exception_handler(exc, context): #自定义的错误处理函数"""exc错误对象context 异常发生时的一些上下文信息"""# 先调用REST framework默认的异常处理方法获得标准错误响应对象response = exception_handler(exc, context) #这个函数是drf提供的,它处理了一些错误,但是如果它处理不了的,它会返回None,所以,如果是None的话,我们需要自己来处理错误# 在此处补充自定义的异常处理if response is None:if isinstance(exc,APIError)#这里就可以记录错误信息了,一般记录到文件中,可以使用日志系统来进行记录# return Respose({'msg':'自定义API错误了'})response.data['status_code'] = response.status_codereturn 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 as drf_exception_handler
from rest_framework import status
from django.db import DatabaseErrordef exception_handler(exc, context):response = drf_exception_handler(exc, context)if response is None:view = context['view'] #出错的方法或者函数名称if isinstance(exc, DatabaseError):print('[%s]: %s' % (view, exc))response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)return response
REST framework定义的异常
APIException
所有异常的父类ParseError
解析错误AuthenticationFailed
认证失败NotAuthenticated
尚未认证PermissionDenied
权限决绝NotFound
未找到MethodNotAllowed
请求方式不支持NotAcceptable
要获取的数据格式不支持Throttled
超过限流次数ValidationError
校验失败
也就是说,上面列出来的异常不需要我们自行处理了,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。
8. 自动生成接口文档
REST framework可以自动帮助我们生成接口文档。
接口文档以网页的方式呈现。
自动接口文档能生成的是继承自APIView
及其子类的视图。
文档:https://www.kernel.org/doc/html/v4.12/core-api/index.html
8.1. 安装依赖
REST framewrok生成接口文档需要coreapi
库的支持。
pip install coreapi
8.2. 设置接口文档访问路径
在总路由中添加接口文档路径。
文档路由对应的视图配置为rest_framework.documentation.include_docs_urls
,
参数title
为接口文档网站的标题。
from rest_framework.documentation import include_docs_urlsurlpatterns = [...path('docs/', include_docs_urls(title='站点页面标题'))
]
如果报错了下面的错误,说明我们缺少一个依赖,配置一下就行了
'AutoSchema' object has no attribute 'get_link'
配置:
REST_FRAMEWORK = {...'DEFAULT_SCHEMA_CLASS': "rest_framework.schemas.AutoSchema",}
8.3. 文档描述说明的定义位置
1) 单一方法的视图,可直接使用类视图的文档字符串,如
class BookListView(generics.ListAPIView):"""get: 返回所有图书信息.post: 添加记录"""#注意,这是在类中声明的注释,如果在方法中你声明了其他注释,会覆盖这个注释的
2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
class BookListCreateView(generics.ListCreateAPIView):"""get:返回所有图书信息.post:新建图书."""
3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):"""list:返回图书列表数据retrieve:返回图书详情数据latest:返回最新的图书数据read:修改图书的阅读量"""
8.4. 访问接口文档网页
浏览器访问 127.0.0.1:8000/docs/,即可看到自动生成的接口文档。
两点说明:
1) 视图集ViewSet
中的retrieve
名称,在接口文档网站中叫做read
2)参数的Description
需要在模型类或序列化器类的字段中以help_text
选项定义,如:
class Student(models.Model):...age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄')...
或 注意,如果你多个应用使用同一个序列化器,可能会导致help_text
的内容显示有些问题,小事情
class StudentSerializer(serializers.ModelSerializer):class Meta:model = Studentfields = "__all__"extra_kwargs = {'age': {'required': True,'help_text': '年龄'}}
这篇关于【django2.0之Rest_Framework框架三】rest_framework认证,权限,限流,过滤,排序,分页,异常处理,生成文档介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!