DjangoRestFramework之认证组件,权限组件,频率组件,分页组件

一 . 认证组件

我们现在知道的认证机制有cookie, session,session比较安全,session的信息是存在服务器上的,
如果用户量足够大的话,服务器的压力也就比较大,并且django的session存到了django_session表中,不是很好操作,现在生产中使用的一个叫做token机制的方式比较多.
可以使用这个机制把token存到用户信息里,当用户登录成功的时候放里面,等他来的时候就要带着这个来,而且们每次来的时候都更新token,防止被拦截.

  我们这里使用一下token,首先要建一个表,和user表一对一关系

  models.py

class User(models.Model):
    username = models.CharField(max_length=16)
    password = models.CharField(max_length=16)
    types = ((1, 'VIP'), (2, 'SVIP'), (3, 'SSVIP'))
    usertype = models.IntegerField(choices=types, default=1)

class UserToken(models.Model):
    user = models.OneToOneField('User')
    token = models.CharField(max_length=64)

  URL

url(r'^login/$', views.LoginView.as_view()),  # 别忘了$符号结尾

  视图函数,每次登录后自动刷新token

import uuid

# 用户登录认证
class UserAuth(APIView):
    RET = {
        'code': None,
        'userinfo': None,
        'msg': None,
        'token': None
    }

    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user_obj = models.User.objects.filter(username=username, password=password).first()
        if user_obj:
            random_str = uuid.uuid4()
            models.UserToken.objects.update_or_create(    # 有就更新,没有就创建
                user=user_obj,
                defaults={
                    'token': random_str,
                }
            )
            self.RET['code'] = 0  # 跟前端约定好,0表示成功
            self.RET['userinfo'] = username
            self.RET['msg'] = 'success'
            self.RET['token'] = random_str
        else:
            self.RET['code'] = -1
            self.RET['userinfo'] = username
            self.RET['msg'] = 'failure'
        return Response(self.RET)

  我们这里写一下DRF的认证组件

from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication
from app01 import models

# drf提供认证失败的异常
class UserAuthToken(BaseAuthentication):

    # authenticate方法是固定的,并且必须写这个名字,是request新对象
    def authenticate(self, request):
        token = request.query_params.get('token')  # 类似于GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if token_obj:
            return token_obj.user, token   # 要么就返回两个值,要么就不返回
        else:
            return AuthenticationFailed('认证失败')  

  我们需要把这个认证组件 写到每一个url对应的视图函数中,加上认证,有token就可以访问,没有就拒绝 

class BookHandle(APIView):
    authentication_classes = [UserAuthToken, ]  #一进到这个函数就进行验证,变量名必须是这个,认证组件需要从所在文件中导入

    # 获取所有数据
    def get(self, request):
        book_obj_list = models.Book.objects.all()
        book_res = BookSerializer(book_obj_list, many=True)
        return Response(book_res.data)

  需要补两张成功与失败的对比图!!!

  全局视图组件(写在settings.py中)

  

二 . 权限组件

  权限组件

from rest_framework.permissions import BasePermission
class UserPermission(BasePermission):
    message = "SVIP才能访问!"  # 变量只能叫做message,权限不够的话返回message里面的数据

    def has_permission(self, request, view):  # view是用权限的视图函数
        if request.user.usertype == 3:   # user表中usertype的字段表示权限级别
            return True  # 通过权限,只能写True或False
        return False  # 没有通过

  视图函数

class BookHandle(APIView):
    permission_classes = [UserPer, ]  # 一进函数就验证,只有有权限的才能访问下面的数据
    # 获取所有数据
    def get(self, request):
        book_obj_list = models.Book.objects.all()
        book_res = BookSerializer(book_obj_list, many=True)
        return Response(book_res.data)

  全局视图权限(写在settings.py文件)

三 . 频率组件 

  内置的throttles类

from rest_framework.throttling import SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"   # 限制访问次数用的
    def get_cache_key(self, request, view):   # 这个方法是固定的

        return self.get_ident(request)

  视图函数

class BookHandle(APIView):

    throttle_classes = [VisitThrottle, ]  # 添加访问频率,需要从该类所在位置引入

    # 获取所有数据
    def get(self, request):
        book_obj_list = models.Book.objects.all()
        book_res = BookSerializer(book_obj_list, many=True)
        return Response(book_res.data)

四 .  分页组件 

  视图函数

from rest_framework.pagination import PageNumberPagination

class BookHandle(APIView):

    # 获取所有数据
    def get(self, request):
        book_obj_list = models.Book.objects.all()
        # 创建分页器对象
        pagenum = PageNumberPagination()
        # 通过分页器的paginate_queryset 方法进行分页
        page_book_list = pagenum.paginate_queryset(book_obj_list, request)
        book_res = BookSerializer(page_book_list, many=True)
        return Response(book_res.data)

  可以在全局限制每页显示多少个

  

  当然了,也可以自定义page_size

from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
    # 下面这些参数只能叫固定的名字
    page_size = 3 #每页数据显示条数
    page_query_param = 'pp'  #http://127.0.0.1:8000/books/?pp=1,查询第一页的数据
    page_size_query_param = 'size' # 用做自定义显示数据http://127.0.0.1:8000/books/?pp=2&size=5 #正常是显示3个,这样写就显示5个
    max_page_size = 10 #最大每页展示多少条,即便是你前端通过page_size_query_param临时调整了page_size的值,
                但是最大也不能超过我们设置的max_page_size的值
class BookHandle(APIView): # 获取所有数据 def get(self, request): book_obj_list = models.Book.objects.all() pagenum = MyPagination() page_book_list = pagenum.paginate_queryset(book_obj_list, request) book_res = BookSerializer(page_book_list, many=True) return Response(book_res.data)

  继承ModelViewSet的视图函数使用分页器

from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import ModelViewSet

from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
    page_size = 3
    page_query_param = 'pp'
    page_size_query_param = 'size'
    max_page_size = 10

class CAuthorHandle(ModelViewSet):
    queryset = models.Author.objects.all()  # 变量名必须是这个
    serializer_class = AuthorSerializer  # 变量名必须是这个
    pagination_class = MyPagination #配置我们自己写的分页类
原文地址:https://www.cnblogs.com/attila/p/10805858.html