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