首页 > 编程语言 > 详细

drf-权限、频率(限流)、过滤、排序、异常处理

时间:2020-07-12 13:20:25      阅读:69      评论:0      收藏:0      [点我收藏+]

1 权限Permissions(权限是在认证之后的)

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

1.1 权限源码分析

# APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的对象方法)
    def check_permissions(self, request):
        # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
        for permission in self.get_permissions():
            # 权限类一定有一个has_permission权限方法,用来做权限认证的
            # 参数:权限对象self、请求对象request、视图类对象
            # 返回值:有权限返回True,无权限返回False
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, message, None)
                )

1.2 自定义权限(和认证一样)

 app_auth.py写一个类,继承BasePermission,重写has_permission

# 写一个类,继承BasePermission,重写has_permission,如果权限通过,就返回True,不通过就返回False
from rest_framework.permissions import BasePermission


class UserPermission(BasePermission):
    def has_permission(self, request, view):    # view是视图类的对象
        # 不是超级用户,不能访问
        # 由于认证已经过了,request内就有user对象了,当前登录用户
        user = request.user  # 当前登录用户
        # 如果该字段用了choice,通过get_字段名_display()就能取出choice后面的中文
        print(user.get_user_type_display())
        if user.user_type == 1:
            return True
        else:
            return False

使用:

# 局部使用
class TestView(APIView):
    permission_classes = [app_auth.UserPermission]
# 全局使用
REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",],
    DEFAULT_PERMISSION_CLASSES: [
        app01.app_auth.UserPermission,
    ],
}
# 局部禁用
class TestView(APIView):
    permission_classes = []

1.3 内置权限以及认证

# 演示一下内置权限的使用:IsAdminUser,控制是否对网站后台有权限的人
# 1 创建超级管理员
# 2 写一个测试视图类
# views.py
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测试数据,超级管理员可以看)

# urls.py
urlpatterns = [
    path(test3/, views.TestView3.as_view()),
]

# 3 超级用户登录到admin,再访问test3就有权限
# 4 正常的话,普通管理员,没有权限看(判断的是is_staff字段)

2 频率限制/限流(Throttling)

可以对接口访问的频次进行限制,以减轻服务器压力。

一般用于付费购买次数,投票等场景使用.

2.1 自定义频率类

2.1.1 编写频率类

 

 

2.2 内置频率类

settings.py设置限制匿名用户访问频次

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",],
    DEFAULT_PERMISSION_CLASSES: [
        app01.app_auth.UserPermission,
    ],
    DEFAULT_THROTTLE_CLASSES: (
        rest_framework.throttling.AnonRateThrottle,
    ),
    DEFAULT_THROTTLE_RATES: {
        anon: 3/m,
    }
}

views.py

class TestView5(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes = [AnonRateThrottle]

    def get(self, request, *args, **kwargs):
        return Response(我是未登录用户,TestView5)

内置频率限制之全局或局部限制登录用户的访问频次

# 需求:未登录用户1分钟访问5次,登录用户一分钟访问10次
全局:在setting中
  DEFAULT_THROTTLE_CLASSES: (
        rest_framework.throttling.AnonRateThrottle,
        rest_framework.throttling.UserRateThrottle
    ),
    DEFAULT_THROTTLE_RATES: {
        user: 10/m,
        anon: 5/m,
    }
        
局部配置:(settings.py中的设置频率的DEFAULT_THROTTLE_RATES还要写)
    然后再在视图类中配一个就行
    throttle_classes = [AnonRateThrottle]

限制的用户

1) AnonRateThrottle

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

使用DEFAULT_THROTTLE_RATES[anon] 来设置频次

2)UserRateThrottle

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

使用DEFAULT_THROTTLE_RATES[user] 来设置频次

3)ScopedRateThrottle

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

3 过滤Filtering

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

# pip3 install django-filter

在配置文件中注册,并设置全局配,或者局部配置

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

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",],
    DEFAULT_PERMISSION_CLASSES: [
        app01.app_auth.UserPermission,
    ],
    DEFAULT_THROTTLE_CLASSES: (
        rest_framework.throttling.AnonRateThrottle,
        rest_framework.throttling.UserRateThrottle,
    ),
    DEFAULT_THROTTLE_RATES: {
        anon: 5/m,
        user: 10/m,
    },
    DEFAULT_FILTER_BACKENDS: (django_filters.rest_framework.DjangoFilterBackend,)   # 全局过滤,之后在视图中指明按照哪个字段过滤
}

views.py

class BookView(ListAPIView):
    authentication_classes = []
    permission_classes = []
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_fields = (name,)  # 配置可以按照哪个字段来过滤

urls.py

urlpatterns = [
    path(books/, views.BookView.as_view()),
]

访问效果

技术分享图片

 过滤的局部配置:

from django_filters.rest_framework import DjangoFilterBackend  # 导入
# 之后在视图中使用
filter_backends = [DjangoFilterBackend]

 4 排序

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

使用方法:

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

前端可以传递的ordering参数,例如:http://127.0.0.1:8000/books2/?ordering=-id(可选字段值需要在ordering_fields中指明)。

局部配置

views.py (局部配置直接在视图中配置)

from rest_framework.generics import ListAPIView
from app01.models import Book
from app01.serializers import BookSerializer
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter    # 排序,依赖于django-filters

# 过滤字段使用
class BookView(ListAPIView):
    authentication_classes = []
    permission_classes = []
    filter_backends = [DjangoFilterBackend]
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_fields = (name, price)  # 配置可以按照哪个字段来过滤

# 排序组件使用
class BookView2(ListAPIView):
    authentication_classes = []
    permission_classes = []
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]   # 局部配置
    ordering_fields = (id, price)    # 排序字段

urls.py

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path(admin/, admin.site.urls),
    # 过滤
    path(books/, views.BookView.as_view()),
    # 排序
    path(books2/, views.BookView2.as_view()),
]

全局配置(settings.py中配置排序,视图中配置排序字段)

settings.py

REST_FRAMEWORK = {
    DEFAULT_FILTER_BACKENDS: (
    rest_framework.filters.OrderingFilter, )
}

views.py

from rest_framework.generics import ListAPIView
from app01.models import Book
from app01.serializers import BookSerializer
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter

# 过滤字段使用
class BookView(ListAPIView):
    authentication_classes = []
    permission_classes = []
    # filter_backends = [DjangoFilterBackend]
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_fields = (name, price)  # 配置可以按照哪个字段来过滤

# 排序组件使用
class BookView2(ListAPIView):
    authentication_classes = []
    permission_classes = []
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # filter_backends = [OrderingFilter]
    ordering_fields = (id, price)    # 排序字段

使用时,url后?ordering参数,参数前加-表示降序

# 使用:
http://127.0.0.1:8000/books2/?ordering=-price
http://127.0.0.1:8000/books2/?ordering=price
http://127.0.0.1:8000/books2/?ordering=-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 = StudentModelSerializer
    filter_fields = (age, sex)
    # 因为局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明,
    # 否则过滤功能会失效
    filter_backends = [OrderingFilter,DjangoFilterBackend]
    ordering_fields = (id, age)

5 异常处理

异常处理用于统一接口返回

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

使用方法:

app_auth.py,自定义异常处理

# 异常处理
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status


def my_exception_handler(exc, context):
    response = exception_handler(exc, context)   # 调用一下原有方法,在原有基础上加处理
    # 两种情况,一个是None,drf没有处理
    # response对象,django处理了,但是处理的不符合咱们的要求
    # print(type(exc))

    if not response:
        if isinstance(exc, ZeroDivisionError):
            return Response(data={status: 777, msg: "除以0的错误" + str(exc)}, status=status.HTTP_400_BAD_REQUEST)
        return Response(data={status: 999, msg: str(exc)}, status=status.HTTP_400_BAD_REQUEST)
    else:
        # return response
        return Response(data={status: 888, msg: response.data.get(detail)}, status=status.HTTP_400_BAD_REQUEST)

全局配置settings.py

REST_FRAMEWORK = {
    # "DEFAULT_AUTHENTICATION_CLASSES": ["app01.app_auth.MyAuthentication", ],
    # ‘DEFAULT_PERMISSION_CLASSES‘: [
    #     ‘app01.app_auth.UserPermission‘,
    # ],
    # ‘DEFAULT_THROTTLE_CLASSES‘: (
    #     ‘rest_framework.throttling.AnonRateThrottle‘,
    # ),

    DEFAULT_THROTTLE_CLASSES: (
        rest_framework.throttling.AnonRateThrottle,
        rest_framework.throttling.UserRateThrottle
    ),
    DEFAULT_THROTTLE_RATES: {
        user: 10/m,
        anon: 5/m,
    },
    DEFAULT_FILTER_BACKENDS: (django_filters.rest_framework.DjangoFilterBackend,),
    EXCEPTION_HANDLER: app01.app_auth.my_exception_handler,    # 异常处理

}

 

drf-权限、频率(限流)、过滤、排序、异常处理

原文:https://www.cnblogs.com/baicai37/p/13281961.html

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