本节内容:
为了方便接下来的学习,我们创建一个新的子应用 four
python manage.py startapp four
因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员.
python manage.py createsuperuser 填一下用户名、邮箱和密码 root 1232@qq.com 123
创建管理员以后,访问admin站点,先修改站点的语言配置
settings.py
访问admin 站点效果:
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 APIView class ExampleView(APIView): # 类属性 authentication_classes = [SessionAuthentication, BasicAuthentication] #也可以写成元祖形式的,到时候我们使用我们自己开发的认证组件的时候,就需要自己写一个认证组件类,然后写在列表中来使用 ...
1.2 自定义认证组件
1.2.1 写一个认证类
需要继承一个基类 BaseAuthentication 然后重写基类中的方法
return 返回的两个值分别为用户信息(xx)和其他信息(oo),可以用一下方法获取
request.user = 'xx'
request.token = 'oo'
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed class APIAuth(BaseAuthentication): def authenticate(self, request): print(request) #<rest_framework.request.Request object at 0x1142bd190> request.user if 1: return 'xx','oo' #request.user = 'xx' request.auth = 'oo' request.token = 'oo' else: raise AuthenticationFailed('认证失败')
全局使用,settings配置文件中使用
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( ... 'four.utils.auth.APIAuth', #类的路径 ), }
局部视图中使用:
from rest_framework.authentication import SessionAuthentication, BasicAuthentication from four.utils.auth import APIAuth class AuthAPIView(APIView): authentication_classes = [APIAuth,] def get(self,request): print('>>>>',request.user) #AnonymousUser 匿名用户,假用户 print('>>>>',request.auth) #AnonymousUser 匿名用户,假用户 #>>>> root return Response({'msg':'hello'})
1 class UserAuth(): 2 def authenticate_header(self,request): 3 pass 4 #authenticate方法固定的,并且必须有个参数,这个参数是新的request对象,不信,看源码 5 def authenticate(self,request): 6 print('搞事情') 7 if 1: 8 #源码中会发现,这个方法会有两个返回值,并且这两个返回值封装到了新的request对象中了,request.user-->用户名 和 request.auth-->token值,这两个值作为认证结束后的返回结果 9 return "chao","asdfasdfasdf" 10 11 class BookView(APIView): 12 #认证组件肯定是在get、post等方法执行之前执行的,还记得源码的地方吗,这个组件是在dispatch的地方调用的,我们是上面写个UserAuth类 13 authentication_classes = [UserAuth,] #认证类可以写多个,一个一个的顺序验证 14 def get(self,request): 15 ''' 16 查看所有书籍 17 :param request: 18 :return: 19 ''' 20 #这样就拿到了上面UserAuth类的authenticate方法的两个返回值 21 print(request.user) 22 print(request.auth) 23 book_obj_list = models.Book.objects.all() 24 s_books = BookSerializers(book_obj_list,many=True) 25 return Response(s_books.data)
-
在执行视图的dispatch()方法前,会先进行视图访问权限的判断
-
可以在配置文件中全局设置默认的权限管理类,如
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 APIView class ExampleView(APIView): permission_classes = (IsAuthenticated,) ...
-
AllowAny 允许所有用户
-
IsAuthenticated 仅通过认证的用户
-
IsAdminUser 仅管理员用户(可以通过admin创建一个用户进行测试)
-
from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.generics import RetrieveAPIView class StudentAPIView(RetrieveAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated]
-
.has_permission(self, request, view)
是否可以访问视图, view表示当前视图对象
-
.has_object_permission(self, request, view, obj)
from rest_framework.permissions import BasePermission class IsXiaoMingPermission(BasePermission): def has_permission(self, request, view): if( request.user.username == "xiaoming" ): return True
from .permissions import IsXiaoMingPermission class StudentViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentSerializer permission_classes = [IsXiaoMingPermission]
认证组件和权限组件的使用流程 认证组件: 1 drf默认自带的认证组件是session那一套 2 自定认证组件 a: 项目中创建一个文件夹,比如叫做xx b: 在xx文件夹中创建一个py文件,比如叫做xxx.py c: 在xxx.py文件中定义一个类,名称随意,比如叫做 class Auth(BaseAuthentication),需要继承drf提供的基础认证类 from rest_framework.authentication import BaseAuthentication d:在认证类中就可以定义一个authenticate 方法 def authenticate(self,request): if 1: return "chao","asdfasdfasdf" e: 全局使用: 在settings.py配置文件中来指定这个类的路径 REST_FRAMEWORK = { # 'DEFAULT_AUTHENTICATION_CLASSES': ( # 'xx.xxx.Auth', # 自定义认证类 # ), } f:局部使用: 在视图类中通过类属性来指定 class IndexView(APIView): authentication_classes = [Auth, ] def get(self, request): print(request.user) print(request.auth) return Response({'xx': '老白'}) 权限组件 :过程基本面一致
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', #匿名用户,未登录的 'rest_framework.throttling.UserRateThrottle' #经过登录之后的用户 ), 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', 'user': '1000/day' } }
源码: {'s': 1, 'm': 60, 'h': 3600, 'd': 86400} m表示分钟,可以写m,也可以写minut
也可以在具体视图中通过throttle_classess属性来配置,如
from rest_framework.throttling import UserRateThrottle from rest_framework.views import APIView class ExampleView(APIView): throttle_classes = (UserRateThrottle,) ...
1) AnonRateThrottle
限制所有匿名未认证用户,使用IP区分用户。
使用DEFAULT_THROTTLE_RATES['anon']
来设置频次
2)UserRateThrottle
限制认证用户,使用User id 来区分。
使用DEFAULT_THROTTLE_RATES['user']
'DEFAULT_THROTTLE_RATES': { 'anon': '3/minute', 'user': '10/minute' }
from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.generics import RetrieveAPIView from rest_framework.throttling import UserRateThrottle class StudentAPIView(RetrieveAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated] throttle_classes = (UserRateThrottle,)
3.4 自定义频率组件
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle import time from rest_framework import exceptions visit_record = {} class VisitThrottle(BaseThrottle): # 限制访问时间 VISIT_TIME = 10 VISIT_COUNT = 3 # 定义方法 方法名和参数不能变 def allow_request(self, request, view): # 获取登录主机的id id = 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 False else: self.history.insert(0, self.now) return True def wait(self): return self.history[-1] + self.VISIT_TIME - self.now
四、过滤组件
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
pip install django-filter
在配置文件中增加过滤后端的设置:
INSTALLED_APPS = [ ... 'django_filters', # 需要注册应用, ] REST_FRAMEWORK = { ... 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
在视图中添加filter_fields属性,指定可以过滤的字段
例如:127.0.0.1:8000/four/students/?sex=1
可以在访问上面的路径查询sex=1的所有数据
class StudentListView(ListAPIView): # def get:return self.list() 查询所有数据 queryset = Student.objects.all() serializer_class = StudentSerializer filter_fields = ('age', 'sex') # 127.0.0.1:8000/four/students/?sex=1
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
示例:
class StudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_backends = [OrderingFilter] ordering_fields = ('id', 'age') # 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 = StudentModelSerializer filter_fields = ('age', 'sex') # 因为filter_backends是局部过滤配置,局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明, # 否则过滤功能会失效 filter_backends = [OrderingFilter,DjangoFilterBackend] ordering_fields = ('id', 'age') # 127.0.0.1:8000/books/?sex=1&ordering=-age