权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。
# 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) )
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 = []
# 演示一下内置权限的使用: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字段)
可以对接口访问的频次进行限制,以减轻服务器压力。
一般用于付费购买次数,投票等场景使用.
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。
对于列表数据可能需要根据字段进行过滤,我们可以通过添加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]
对于列表数据,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
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‘)
异常处理用于统一接口返回
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‘, # 异常处理 }
原文:https://www.cnblogs.com/baicai37/p/13281961.html