django之restframework使用 (三)组件

 认证与权限组件

认证组件

局部视图认证

在app01.service.auth.py:

class Authentication(BaseAuthentication):
 
    def authenticate(self,request):
        token=request._request.GET.get("token")
        token_obj=UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed("验证失败!")
        return (token_obj.user,token_obj)

 在views.py:

def get_random_str(user):
    import hashlib,time
    ctime=str(time.time())
 
    md5=hashlib.md5(bytes(user,encoding="utf8"))
    md5.update(bytes(ctime,encoding="utf8"))
 
    return md5.hexdigest()
 
 
from app01.service.auth import *
 
from django.http import JsonResponse
class LoginViewSet(APIView):
    authentication_classes = [Authentication,]
    def post(self,request,*args,**kwargs):
        res={"code":1000,"msg":None}
        try:
            user=request._request.POST.get("user")
            pwd=request._request.POST.get("pwd")
            user_obj=UserInfo.objects.filter(user=user,pwd=pwd).first()
            print(user,pwd,user_obj)
            if not user_obj:
                res["code"]=1001
                res["msg"]="用户名或者密码错误"
            else:
                token=get_random_str(user)
                UserToken.objects.update_or_create(user=user_obj,defaults={"token":token})
                res["token"]=token
 
        except Exception as e:
            res["code"]=1002
            res["msg"]=e
 
        return JsonResponse(res,json_dumps_params={"ensure_ascii":False})

全局视图认证组件

settings.py配置如下:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
}

 全局视图下view中的LoginView

class LoginView(APIView):
    authentication_classes = []
    def post(self,request):
        print('运行POST')
        name=request.data.get("name")
        pwd=request.data.get("pwd")
        user=User.objects.filter(name=name,pwd=pwd).first()
        res = {"state_code": 1000, "msg": None}
        if user:
            random_str=get_random_str(user.name)
            token=Token.objects.update_or_create(user=user,defaults={"token":random_str})
            res["token"]=random_str
        else:
            res["state_code"]=1001 #错误状态码
            res["msg"] = "用户名或者密码错误"

        import json
        return Response(json.dumps(res,ensure_ascii=False))
class AuthorModelView(viewsets.ModelViewSet):

    authentication_classes = [TokenAuth,]
    permission_classes=[SVIPPermission,]
    #throttle_classes = [VisitRateThrottle]    # 限制某个IP每分钟访问次数不能超过20次
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

 权限组件

app01.utils.py

from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
    message="SVIP才能访问!"
    def has_permission(self, request, view):
        if request.user.user_type==3:
            return True
        return False

 views.py

class AuthorModelView(viewsets.ModelViewSet):

    authentication_classes = [TokenAuth,]
    permission_classes=[SVIPPermission,]
    #throttle_classes = [VisitRateThrottle]    # 限制某个IP每分钟访问次数不能超过20次
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

 全局视图权限

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}

 如果想添加白名单,在该类下加上permission_classes =[ ]              ,        源码找的时候就会先找这里

throttle(访问频率)组件

views.py

VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):
        remote_addr = request.META.get('REMOTE_ADDR')
        print('remote_addr',remote_addr)
        import time
        ctime=time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr]=[ctime,] #列表
            return True

        history=VISIT_RECORD.get(remote_addr)
        print('history',history)
        self.history=history

        while history and history[-1]<ctime-60:  #时间大于60秒之前的
            history.pop()  #删除

        if len(history)<3:  #如果一分钟内访问的次数小于3,就把当前时间加入到history中
            history.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime=time.time()
        return 60 - (ctime-self.history[-1])
class AuthorModelView(viewsets.ModelViewSet):

    authentication_classes = [TokenAuth,]
    permission_classes=[SVIPPermission,]
    throttle_classes = [VisitThrottle,]    # 限制某个IP每分钟访问次数不能超过20次
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

 全局视图throttle

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}

内置throttle类 

views.py中

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)
class AuthorModelView(viewsets.ModelViewSet):

    authentication_classes = [TokenAuth,]
    permission_classes=[SVIPPermission,]
    throttle_classes = [VisitThrottle,]    # 限制某个IP每分钟访问次数不能超过20次
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

 setting中

REST_FRAMEWORK={
    # "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    # "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    # "DEFAULT_THROTTLE_CLASSES":["app01.utils.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

 解析器

对得到的数据进行反序列化

局部视图

rom rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
    parser_classes = [FormParser,JSONParser]  #只能解析列表中的
    queryset = Publish.objects.all()
    serializer_class = PublshSerializers
    def post(self, request, *args, **kwargs):
        print("request.data",request.data)
        return self.create(request, *args, **kwargs)

 全局视图

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    },
    "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
}

 URL的控制

url中

from django.conf.urls import url, include
from rest_framework import routers
from tutorial.quickstart import views

router = routers.DefaultRouter()
router.register(r'authors', views.AuthorsViewSet)


urlpatterns = [
    url(r'^', include(router.urls)),

 只要注册了router.register,就会有相对应的

path('authors/',views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'),
re_path(r'^authors/(?P<pk>d+)/$',views.AuthorModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'}),name='authors_detail'),

 并且还相应的增加了其他两条restframework的测试url

分页

简单分页

继承APIView类的视图中添加分页

views.py

from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
    # 定义一个PageNumberPagination的子类
    # 如需改变参数,重写其属性即可
    page_size = 6       #每页显示条数
    page_query_param = 'page'   # url中的参数的key
    page_size_query_param="size"    # 可以在url中使用size参数临时改变当页显示的数目
    max_page_size=10 # 可以在url中使用size参数临时改变当页显示的数目,但是最大只能显示10条
 
 
class AuthorsView(APIView):
    def get(self,request):
        '''分页展示作者列表'''
        author_list = models.Author.objects.all()
        # 分页
        # 实例化一个自己定义的MyPageNumberPagination对象
        pnp = MyPageNumberPagination()
        # 调用paginate_queryset方法来生成新的author_list
        # 参数分别为,author_list,request以及当前的视图
        page_author_list = pnp.paginate_queryset(author_list,request,self)
        # 在将新生成的page_author_list序列化
        auts = serializer.AuthorModelSerializers(page_author_list,many=True)
        return Response(auts.data)

 继承ModelViewSet类的视图中添加分页

views.py

from rest_framework.pagination import PageNumberPagination
class Mypagination(PageNumberPagination):
        page_size = 1
        page_query_param = 'page'
        page_size_query_param = "size"
        max_page_size = 5

from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer
    pagination_class = Mypagination

如果我们的视图继承了ModelViewSet类,那么如需分页的时候,只需要在视图类中加入配置参数即可,如下:

   

 

pagination_class = MyPageNumberPagination    

注意:

    1、MyPageNumberPagination类是我们自己定义的类,见上面一个示例。

    2、pagination_class后面直接跟上类名即可,无需加列表(因为分页不想其他组件,分页只可能有一个)

全局配置分页属性

只需要在REST_FRAMEWORK配置中加入 配置属性的键值对即可,如下:

REST_FRAMEWORK = {
    .....
    "PAGE_SIZE":1
}

 偏移分页

from rest_framework.pagination import LimitOffsetPagination   # ?offset=1&limit=10

用时只需知名用哪个分页器

响应器

from rest_framework.response import Response

 帮助我们渲染出页面,更方便操作、调试数据

I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我

原文地址:https://www.cnblogs.com/weidaijie/p/10412480.html