#基本视图 #抽取基类 from rest_framework.response import Response from rest_framework.views import APIView from app1.models import * from app1.Myserializer import BookSerializer from app1.Myserializer import PublishSerializer class List(): def list(self,request,*args,**kwargs): response = {'status':100,'msg':'查询成功'} g = self.model g_ser = self.model_ser(instance=g,many=True) response['data'] = g_ser.data return Response(response) class Create(): def create(self,request,*args,**kwargs): response = {'status': 100, 'msg': '新增成功'} try: p_ser = self.model_ser(data=request.data) if p_ser.is_valid(): p_ser.save() response['data'] = p_ser.data else: response['msg'] = p_ser.errors except Exception as e: response['msg'] = str(e) return Response(response) #图书查询,新增 class BooksView(List,Create,APIView): model = Book.objects.all() model_ser = BookSerializer def get(self,request,*args,**kwargs): return self.list(request,*args,**kwargs) def post(self,request,*args,**kwargs): return self.create(request,*args,**kwargs) #出版社查询,新增 class PublishView(List,Create,APIView): model = Publish.objects.all() model_ser = PublishSerializer def get(self,request,*args,**kwargs): return self.list(request,*args,**kwargs) def post(self,request,*args,**kwargs): return self.create(request,*args,**kwargs)
from app1.models import * from app1.Myserializer import BookSerializer from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin from rest_framework.generics import GenericAPIView #ListModelMixin:获取所有 CreateModelMixin:新增 RetrieveModelMixin:获取单本 UpdateModelMixin:更新 DestroyModelMixin:删除 class BooksView(ListModelMixin,CreateModelMixin,GenericAPIView): serializer_class = BookSerializer queryset = Book.objects.all() #获取所有图书 def get(self,request,*args,**kwargs): return self.list(request,*args,**kwargs) #新增图书 def post(self,request,*args,**kwargs): return self.create(request,*args,**kwargs) class BookView(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView): serializer_class = BookSerializer queryset = Book.objects.all() #获取单本 def get(self,request,*args,**kwargs): return self.retrieve(request,*args,**kwargs) #更新图书 def put(self, request, *args, **kwargs): return self.update(request,*args,**kwargs) #删除图书 def delete(self,request,*args,**kwargs): return self.destroy(request,*args,**kwargs)
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView #获取所有和新增图书 class BooksView(ListCreateAPIView): serializer_class = BookSerializer queryset = Book.objects.all() #查询单个图书,更新,删除 class BookView(RetrieveUpdateDestroyAPIView): serializer_class = BookSerializer queryset = Book.objects.all()
from app1.models import * from app1.Myserializer import BookSerializer from rest_framework.viewsets import ModelViewSet class BooksView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer #路由层路由配置 url(r'^books/$', views.BooksView.as_view({'get':'list','post':'create'})), url(r'^books/(?P<pk>\d+)$',\ views.BooksView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
要用ViewSetMixin,路由跟之前写法不一样了 url(r'^test', views.Publish.as_view({'get':'aa'})), 视图类中 from rest_framework.viewsets import ViewSetMixin class Publish(ViewSetMixin,APIView): def aa(self,request): return HttpResponse('aa')
-什么是认证?是用来干什么的? 校验用户是否是我的登录用户 -drf源码中找,认证如何实现的 -APIView的dispach方法---》self.initial(request, *args, **kwargs)----》400行self.perform_authentication(request)---》APIView的perform_authentication(request)----》request.user(request是新的request)---->去Request类中找user,执行--->self._authenticate()(self是新的reqeust对象)---->Request类的_authenticate(self)方法
''' 1.①写一个认证类MyAuthentication,继承BaseAuthentication ②类的内部重写authenticate方法 ③在authenticate方法中写认证逻辑,认证通过,返回None,认证不通过,抛异常 ④校验通过,也可以返回当前登录的用户和auth,这样操作,在视图类中,可以通过request.user,获取到当前登录的用户 ⑤一旦返回了值,后续的认证类就不会再走了 ''' ''' 2.authentication_classes查找顺序(认证类的查找顺序): ①先在自己类当中找:authentication_classes=[MyAuthentication] ②如果自己当中没有配置,去去项目settings.py中去找 ③如果项目setting中没有配置,去drf的setting中找 ''' ''' 3.最终在认证中的使用 局部使用: -在视图类中配置:authentication_classes=[MyAuthentication] 全局使用: -在setting.py中配置: REST_FRAMEWORK={ 'DEFAULT_AUTHENTICATION_CLASSES':['app1.MyAuth.MyAuthentication'] } 全局使用了局部禁用: -在视图类中配置:authentication_classes=[] ''' from rest_framework.response import Response from app1.models import * from rest_framework.views import APIView import uuid from rest_framework.exceptions import AuthenticationFailed from rest_framework.authentication import BaseAuthentication class MyAuthentication(BaseAuthentication): def authenticate(self,request): #认证相关的东西 #校验请求是否携带正确的token #取出token token = request.GET.get('token') #校验该次请求是否携带正确的token ret = UserToken.objects.filter(token=token).first() if ret: #正常通过认证的用户 return ret.user,ret else: #没有登录或非法用户 raise AuthenticationFailed('您没有通过认证') class BooksView(APIView): #某个视图类需要登陆后才能查看,只需要在视图类加入下面代码 authentication_classes=[MyAuthentication] def get(self,request): return Response('ok') class Login(APIView): def post(self,request): response={'status':100,'msg':None} name = request.data.get('name') pwd = request.data.get('pwd') #去数据库校验数据是否存在 user = User.objects.filter(name=name,pwd=pwd).first() if user: #正常用户登录成功 #返回唯一的随机字符串 token = uuid.uuid4() #生成随机的字符串存到数据库中,如果存在更新token,不存在新增一条 # 根据user去查询,如果查到数据,更新defaults中的数据,如果查不到,新增一条数据 ret = UserToken.objects.update_or_create(user=user,defaults={'token':token}) response['msg'] = '登录成功' response['token'] = token else: response['status'] = 101 response['msg'] = '账号或密码错误' return Response(response) #请求 #http://127.0.0.1:8000/books/?token=735061c3-733d-463d-8158-ccfa2e13f539 #token匹配成功就会得到图书信息,否则返回没有通过认证 #加了 authentication_classes=[MyAuthentication] 这句代码,直接访问http://127.0.0.1:8000/books/ 会返回没有通过认证
''' 权限是什么? 比如只有超级用户可以访问books这个接口 使用: ①写一个权限类MyPermissions,继承BasePermission ②类的内部重写has_permission方法 ③在has_permission方法内部写权限逻辑,通过返回True,失败返回False ''' user表 class User(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) choice=((1,'超级用户'),(2,'普通用户'),(3,'穷逼用户')) type = models.IntegerField(choices=choice,null=True) from rest_framework.permissions import BasePermission class MyPermissions(BasePermission): def has_permission(self, request, view): #是否为超级用户 if request.user.type == 1: #如何取type对应的文字 get_字段名_display() user_type = request.user.get_type_display() #超级用户校验通过返回True return True else: #校验失败返回False return False ''' 最终的使用 局部使用: -在视图类中配置:permission_classes=[MyPermissions] 全局使用: -在settings.py中配置: REST_FRAMEWORK={ 'DEFAULT_PERMISSION_CLASSES':['app1.MyAuth.MyPermissions'] } 全局使用了局部禁用: -在视图类中配置:permission_classes=[]
''' 频率是什么? -同一段时间内,只能访问多少次 ''' 频率组件的使用: ①写一个频率类Mythrottling,继承SimpleRetaThrottle ②重写get_cache_key方法,方法返回什么,频率组件就以什么做限制(比如返回ip,就以ip做限制.返回user_id,就会以用户id做限制) from rest_framework.throttling import SimpleRateThrottle class MyThrottling(SimpleRateThrottle): scope = 'xxx' def get_cache_key(self, request, view): return request.META.get('REMOTE_ADDR') #返回客户端ip地址 ③在setings.py中配置: 'DEFAULT_THROTTLE_CLASSES':{ 'xxx:'3/m' #每分钟三次 } ④局部使用: -在视图类中配置:throttle_classes=[MyThrottling] 全局使用: -在settings.py中配置 REST_FRAMEWORK={ 'DEFAULT_THROTTLE_CLASSES':['app1.MyAuth.MyThrottling'] } 全局使用了局部禁用: -在视图类中配置:throttle_classes=[]
''' 频率控制的逻辑 某个ip地址一分钟只能访问三次 {ip地址1:[第三次访问的时间,第二次访问的时间,第一次访问的时间],ip地址2:[]} (1)取出访问者ip (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走 (3)循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把列表中最后一个数用pop去掉,这样列表中只有60s以内的访问时间, (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败 ''' from rest_framework.throttling import BaseThrottle class MyThrottling(BaseThrottle): #访问者ip字典 VISIT_RECORD = {} def __init__(self): #访问者ip对应的时间列表 self.history=None def allow_request(self, request, view): #(1)取出访问者ip ip = request.META.get('REMOTE_ADDR') #获取当前时间 import time ctime = time.time() #(2)判断当前ip不在访问字典里,添加进去,并且直接返回True, 表示第一次访问,在字典里,继续往下走 if ip not in self.VISIT_RECORD: self.VISIT_RECORD[ip]=[ctime,] return True #获取当前访问者的时间列表self.history self.history = self.VISIT_RECORD.get(ip) #(3)循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把列表中最后一个数据用pop去掉,这样列表中只有60s以内的访问时间 while self.history and ctime-self.history[-1] > 60: self.history.pop() #(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 #(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败 if len(self.history) < 3: self.history.insert(0,ctime) return True else: return False #还要等待的时间 def wait(self): import time ctime = time.time() return 60 - (ctime-self.history[-1])