认证与权限组件
认证组件
局部视图认证
在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
帮助我们渲染出页面,更方便操作、调试数据