Rest Framework

目录导航

  一、RESTful 规范

  二、APIView 组件

  三、序列化组件

  四、认证组件

  五、权限组件

  六、频率组件

  七、分页器组件

 

一、RESTful 规范

  •  什么是RESTful规范:

    •  REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
    •  REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
    •  REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
    •  所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
    •  对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

 

  • RESTful API 设计:

    •    API与用户的通信协议,总是使用HTTPs协议。
    •   域名
      • https://api.example.com                         尽量将API部署在专用域名(会存在跨域问题)
      • https://example.org/api/                        API很简单
    •   版本 
      • URL,如:https://api.example.com/v1/
      • 请求头                                                  跨域时,引发发送多次请求
    •   路径,视网络上任何东西都是资源,均使用名词表示(可复数)
      • https://api.example.com/v1/zoos
      • https://api.example.com/v1/animals
      • https://api.example.com/v1/employees
    •   method
      • GET      :从服务器取出资源(一项或多项)
      • POST    :在服务器新建一个资源
      • PUT      :在服务器更新资源(客户端提供改变后的完整资源)
      • PATCH  :在服务器更新资源(客户端提供改变的属性)
      • DELETE :从服务器删除资源
    •   过滤,通过在url上传参的形式传递搜索条件
      • https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
      • https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
      • https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
      • https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
      • https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
    •   状态码
      '''200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)204 NO CONTENT - [DELETE]:用户删除数据成功。400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html'''
    •   错误处理,应返回错误信息,error当做key。
    •   返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
      • GET /collection:返回资源对象的列表(数组)
      • GET /collection/resource:返回单个资源对象
      • POST /collection:返回新生成的资源对象
      • PUT /collection/resource:返回完整的资源对象
      • PATCH /collection/resource:返回完整的资源对象
      • DELETE /collection/resource:返回一个空文档
    •   Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
      • {"link": {
          "rel":   "collection https://www.example.com/zoos",
          "href":  "https://api.example.com/zoos",
          "title""List of zoos",
          "type":  "application/vnd.yourformat+json"
        }}
  • 基于Django实现

1 urlpatterns = [
2     url(r'^users/$', views.Users.as_view()),
3     url(r'^users2/$', views.user2),
4 
5 ]
路由系统配置
 1 import json
 2 
 3 def  user2(request):
 4     if request.method=='GET':
 5         dic = {'status':200,'name': 'lqz2', 'age': 18}
 6         return HttpResponse(json.dumps(dic))
 7     elif request.method=='POST':
 8         dic = {'status': 200, 'msg': '修改成功'}
 9         return JsonResponse(dic)
10 
11 class Users(View):
12     def get(self, request):
13         dic = {'status':200,'name': 'lqz', 'age': 18}
14         return HttpResponse(json.dumps(dic))
15 
16     def post(self, request):
17         dic = {'status': 200, 'msg': '修改成功'}
18         return JsonResponse(dic)
views.py

 

 

二、APIView 组件

  •  安装djangorestframework

    • 方式一:pip3 install djangorestframework
    • 方式二:pycharm图形化界面安装
    • 方式三:pycharm命令行下安装(装在当前工程所用的解释器下)
  • djangorestframework的APIView分析

 1 @classmethod
 2     def as_view(cls, **initkwargs):
 3         """
 4         Store the original class on the view function.
 5 
 6         This allows us to discover information about the view when we do URL
 7         reverse lookups.  Used for breadcrumb generation.
 8         """
 9         if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
10             def force_evaluation():
11                 raise RuntimeError(
12                     'Do not evaluate the `.queryset` attribute directly, '
13                     'as the result will be cached and reused between requests. '
14                     'Use `.all()` or call `.get_queryset()` instead.'
15                 )
16             cls.queryset._fetch_all = force_evaluation
17 
18         view = super(APIView, cls).as_view(**initkwargs)
19         view.cls = cls
20         view.initkwargs = initkwargs
21 
22         # Note: session based authentication is explicitly CSRF validated,
23         # all other authentication is CSRF exempt.
24         return csrf_exempt(view)
as_view方法
 1 def dispatch(self, request, *args, **kwargs):
 2         """
 3         `.dispatch()` is pretty much the same as Django's regular dispatch,
 4         but with extra hooks for startup, finalize, and exception handling.
 5         """
 6         self.args = args
 7         self.kwargs = kwargs
 8         request = self.initialize_request(request, *args, **kwargs)
 9         self.request = request
10         self.headers = self.default_response_headers  # deprecate?
11 
12         try:
13             self.initial(request, *args, **kwargs)
14 
15             # Get the appropriate handler method
16             if request.method.lower() in self.http_method_names:
17                 handler = getattr(self, request.method.lower(),
18                                   self.http_method_not_allowed)
19             else:
20                 handler = self.http_method_not_allowed
21 
22             response = handler(request, *args, **kwargs)
23 
24         except Exception as exc:
25             response = self.handle_exception(exc)
26 
27         self.response = self.finalize_response(request, response, *args, **kwargs)
28         return self.response
dispatch
def initialize_request(self, request, *args, **kwargs):"""Returns the initial request object."""parser_context = self.get_parser_context(request)return Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)
initialize_request
 1 def initial(self, request, *args, **kwargs):
 2         """
 3         Runs anything that needs to occur prior to calling the method handler.
 4         """
 5         self.format_kwarg = self.get_format_suffix(**kwargs)
 6 
 7         # Perform content negotiation and store the accepted info on the request
 8         neg = self.perform_content_negotiation(request)
 9         request.accepted_renderer, request.accepted_media_type = neg
10 
11         # Determine the API version, if versioning is in use.
12         version, scheme = self.determine_version(request, *args, **kwargs)
13         request.version, request.versioning_scheme = version, scheme
14 
15         # Ensure that the incoming request is permitted
16         self.perform_authentication(request)
17         self.check_permissions(request)
18         self.check_throttles(request)
initial方法(内部调用认证,权限和频率)

 

 

三、序列化组件

  • rest-framework序列化之Serializer

 1 from django.db import models
 2 
 3 # Create your models here.
 4 
 5 
 6 class Book(models.Model):
 7     title=models.CharField(max_length=32)
 8     price=models.IntegerField()
 9     pub_date=models.DateField()
10     publish=models.ForeignKey("Publish")
11     authors=models.ManyToManyField("Author")
12     def __str__(self):
13         return self.title
14 
15 class Publish(models.Model):
16     name=models.CharField(max_length=32)
17     email=models.EmailField()
18     def __str__(self):
19         return self.name
20 
21 class Author(models.Model):
22     name=models.CharField(max_length=32)
23     age=models.IntegerField()
24     def __str__(self):
25         return self.name
models.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from .models import *
 4 from django.shortcuts import HttpResponse
 5 from django.core import serializers
 6 
 7 
 8 from rest_framework import serializers
 9 
10 class BookSerializers(serializers.Serializer):
11     title=serializers.CharField(max_length=32)
12     price=serializers.IntegerField()
13     pub_date=serializers.DateField()
14     publish=serializers.CharField(source="publish.name")
15     #authors=serializers.CharField(source="authors.all")
16     authors=serializers.SerializerMethodField()
17     def get_authors(self,obj):
18         temp=[]
19         for author in obj.authors.all():
20             temp.append(author.name)
21         return temp
22   #此处可以继续用author的Serializers,
23   # def get_authors(self,obj):
24     #     ret=obj.authors.all()
25     #     ss=AuthorSerializer(ret,many=True)
26     #     return ss.data
27 
28 class BookViewSet(APIView):
29 
30     def get(self,request,*args,**kwargs):
31         book_list=Book.objects.all()
32         # 序列化方式1:
33         # from django.forms.models import model_to_dict
34         # import json
35         # data=[]
36         # for obj in book_list:
37         #     data.append(model_to_dict(obj))
38         # print(data)
39         # return HttpResponse("ok")
40 
41         # 序列化方式2:
42         # data=serializers.serialize("json",book_list)
43         # return HttpResponse(data)
44 
45         # 序列化方式3:
46         bs=BookSerializers(book_list,many=True)     #many=True代表有多条数据,如果只有一条数据,many=False
47         return Response(bs.data)
48      # 序列化方式4: 
49       # ret=models.Book.objects.all().values('nid','title')
50      # dd=list(ret)
51         # return HttpResponse(json.dumps(dd))
views.py

    注意:

      source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))如在模型中定义一个方法,直接可以在在source指定执行

        

class UserInfo(models.Model):user_type_choices = ((1,'普通用户'),(2,'VIP'),(3,'SVIP'),)user_type = models.IntegerField(choices=user_type_choices)username = models.CharField(max_length=32,unique=True)password = models.CharField(max_length=64)#视图
ret=models.UserInfo.objects.filter(pk=1).first()
aa=ret.get_user_type_display()#serializer
xx=serializers.CharField(source='get_user_type_display')
View Code

 

  • rest-framework序列化之ModelSerializer

 1 class BookSerializers(serializers.ModelSerializer):
 2     class Meta:
 3         model = models.Book
 4         # fields = "__all__"
 5         fields=['nid','title','authors','publish']
 6         # exclude=('nid',)   #不能跟fields同时用
 7         # depth = 1    #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
 8     publish=serializers.SerializerMethodField()
 9     def get_publish(self,obj):
10         return obj.publish.name
11     authors=serializers.SerializerMethodField()
12     def get_authors(self,obj):
13         ret=obj.authors.all()
14         ss=AuthorSerializer(ret,many=True)
15         return ss.data

 

  • 生成hypermedialink(极少数)

 1 class BookSerializers(serializers.ModelSerializer):
 2     class Meta:
 3         model = models.Book
 4         fields = "__all__"
 5     # 生成连接,直接查看出版社详情
 6     publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id', lookup_url_kwarg='pkk')
 7     authors=serializers.SerializerMethodField()
 8     def get_authors(self,obj):
 9         ret=obj.authors.all()
10         ss=AuthorSerializer(ret,many=True)
11         return ss.data
12 #--------------
13 
14 res=BookSerializers(ret,many=True,context={'request': request})
15 
16 #--------------
17 
18 class Publish(APIView):
19     def get(self,request,pkk):
20         print(pkk)
21         return HttpResponse('ok')
22 #----路由---
23 url(r'^publish/(?P<pkk>\d+)$', views.Publish.as_view(),name='ttt'),

 

  • 序列化组件之请求数据校验和保存功能

class BookSerializers(serializers.ModelSerializer):class Meta:model=Bookfields="__all__"#————————
class BookView(APIView):def post(self, request):# 添加一条数据print(request.data)bs=BookSerializers(data=request.data)if bs.is_valid():bs.save()  # 生成记录return Response(bs.data)else:return Response(bs.errors)
class BookSerializer1(serializers.Serializer):title=serializers.CharField(error_messages={'required': '标题不能为空'})#这种方式要保存,必须重写create方法

   通过源码查看留的校验字段的钩子函数:

 1 #is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)
 2 def validate_title(self, value):
 3         from rest_framework import exceptions
 4         raise exceptions.ValidationError('看你不顺眼')
 5         return value
 6 
 7 #全局
 8 def validate(self, attrs):
 9     from rest_framework import exceptions
10     if attrs.get('title')== attrs.get('title2'):
11         return attrs
12     else:
13         raise exceptions.ValidationError('不想等啊')

 

  • 序列化组件源码分析

1 '''
2 序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
3 序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
4 Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
5 再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
6 当参数传过去,判断是方法就加括号执行,是属性就把值取出来
7 '''

    图书的增删查改resful接口:

 1 class BookSerializers(serializers.ModelSerializer):
 2     class Meta:
 3         model=models.Book
 4         fields='__all__'
 5 
 6 
 7 class BookView(APIView):
 8 
 9     def get(self, request):
10         book_list = models.Book.objects.all()
11         bs = BookSerializers(book_list, many=True)
12         # 序列化数据
13 
14         return Response(bs.data)
15 
16     def post(self, request):
17         # 添加一条数据
18         print(request.data)
19 
20         bs=BookSerializers(data=request.data)
21         if bs.is_valid():
22             bs.save()  # 生成记录
23             return Response(bs.data)
24         else:
25 
26             return Response(bs.errors)
27 
28 class BookDetailView(APIView):
29     def get(self,request,pk):
30         book_obj=models.Book.objects.filter(pk=pk).first()
31         bs=BookSerializers(book_obj,many=False)
32         return Response(bs.data)
33     def put(self,request,pk):
34         book_obj = models.Book.objects.filter(pk=pk).first()
35 
36         bs=BookSerializers(data=request.data,instance=book_obj)
37         if bs.is_valid():
38             bs.save() # update
39             return Response(bs.data)
40         else:
41             return Response(bs.errors)
42     def delete(self,request,pk):
43         models.Book.objects.filter(pk=pk).delete()
44 
45         return Response("")
views.py
1     url(r'^books/$', views.BookView.as_view()),
2     url(r'^books/(?P<pk>\d+)$', views.BookDetailView.as_view()),
urls.py

 

 四、认证组件

  • 认证简介

      只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录,就不能查看,这时候需要用到认证组件

  • 局部使用

1 class User(models.Model):
2     username=models.CharField(max_length=32)
3     password=models.CharField(max_length=32)
4     user_type=models.IntegerField(choices=((1,'超级用户'),(2,'普通用户'),(3,'二笔用户')))
5 
6 class UserToken(models.Model):
7     user=models.OneToOneField(to='User')
8     token=models.CharField(max_length=64)
models.py
 1 from rest_framework.authentication import BaseAuthentication
 2 class TokenAuth():
 3     def authenticate(self, request):
 4         token = request.GET.get('token')
 5         token_obj = models.UserToken.objects.filter(token=token).first()
 6         if token_obj:
 7             return
 8         else:
 9             raise AuthenticationFailed('认证失败')
10     def authenticate_header(self,request):
11         pass
新建认证类(验证通过return两个参数)
 1 def get_random(name):
 2     import hashlib
 3     import time
 4     md=hashlib.md5()
 5     md.update(bytes(str(time.time()),encoding='utf-8'))
 6     md.update(bytes(name,encoding='utf-8'))
 7     return md.hexdigest()
 8 class Login(APIView):
 9     def post(self,reuquest):
10         back_msg={'status':1001,'msg':None}
11         try:
12             name=reuquest.data.get('name')
13             pwd=reuquest.data.get('pwd')
14             user=models.User.objects.filter(username=name,password=pwd).first()
15             if user:
16                 token=get_random(name)
17                 models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
18                 back_msg['status']='1000'
19                 back_msg['msg']='登录成功'
20                 back_msg['token']=token
21             else:
22                 back_msg['msg'] = '用户名或密码错误'
23         except Exception as e:
24             back_msg['msg']=str(e)
25         return Response(back_msg)
26 
27 
28 
29 class Course(APIView):
30     authentication_classes = [TokenAuth, ]
31 
32     def get(self, request):
33         return HttpResponse('get')
34 
35     def post(self, request):
36         return HttpResponse('post')
views.py
 1 def get_token(id,salt='123'):
 2     import hashlib
 3     md=hashlib.md5()
 4     md.update(bytes(str(id),encoding='utf-8'))
 5     md.update(bytes(salt,encoding='utf-8'))
 6 
 7     return md.hexdigest()+'|'+str(id)
 8 
 9 def check_token(token,salt='123'):
10     ll=token.split('|')
11     import hashlib
12     md=hashlib.md5()
13     md.update(bytes(ll[-1],encoding='utf-8'))
14     md.update(bytes(salt,encoding='utf-8'))
15     if ll[0]==md.hexdigest():
16         return True
17     else:
18         return False
19 
20 class TokenAuth():
21     def authenticate(self, request):
22         token = request.GET.get('token')
23         success=check_token(token)
24         if success:
25             return
26         else:
27             raise AuthenticationFailed('认证失败')
28     def authenticate_header(self,request):
29         pass
30 class Login(APIView):
31     def post(self,reuquest):
32         back_msg={'status':1001,'msg':None}
33         try:
34             name=reuquest.data.get('name')
35             pwd=reuquest.data.get('pwd')
36             user=models.User.objects.filter(username=name,password=pwd).first()
37             if user:
38                 token=get_token(user.pk)
39                 # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
40                 back_msg['status']='1000'
41                 back_msg['msg']='登录成功'
42                 back_msg['token']=token
43             else:
44                 back_msg['msg'] = '用户名或密码错误'
45         except Exception as e:
46             back_msg['msg']=str(e)
47         return Response(back_msg)
48 from rest_framework.authentication import BaseAuthentication
49 class TokenAuth():
50     def authenticate(self, request):
51         token = request.GET.get('token')
52         token_obj = models.UserToken.objects.filter(token=token).first()
53         if token_obj:
54             return
55         else:
56             raise AuthenticationFailed('认证失败')
57     def authenticate_header(self,request):
58         pass
59 
60 class Course(APIView):
61     authentication_classes = [TokenAuth, ]
62 
63     def get(self, request):
64         return HttpResponse('get')
65 
66     def post(self, request):
67         return HttpResponse('post')
不存数据库的token验证

    总结:局部使用,只需要在视图类里加入:

     authentication_classes = [TokenAuth, ] 

  • 全局使用

REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
}
  • 源码分析

 1 #Request对象的user方法
 2 @property
 3 def user(self):
 4 the authentication classes provided to the request.
 5         if not hasattr(self, '_user'):
 6             with wrap_attributeerrors():
 7                 self._authenticate()
 8         return self._user
 9 
10 def _authenticate(self):
11         for authenticator in self.authenticators:
12             try:
13                 user_auth_tuple = authenticator.authenticate(self)
14             except exceptions.APIException:
15                 self._not_authenticated()
16                 raise
17             #认证成功,可以返回一个元组,但必须是最后一个验证类才能返回
18             if user_auth_tuple is not None:
19                 self._authenticator = authenticator
20                 self.user, self.auth = user_auth_tuple
21                 return
22 
23         self._not_authenticated()
View Code

self.authenticators

    def get_authenticators(self):return [auth() for auth in self.authentication_classes]

认证类使用顺序:先用视图类中的验证类,再用settings里配置的验证类,最后用默认的验证类

 

五、权限组件

  • 权限简介

      只用超级用户才能访问指定的数据,普通用户不能访问,所以就要有权限组件对其限制

  • 局部使用

 1 from rest_framework.permissions import BasePermission
 2 class UserPermission(BasePermission):
 3     message = '不是超级用户,查看不了'
 4     def has_permission(self, request, view):
 5         # user_type = request.user.get_user_type_display()
 6         # if user_type == '超级用户':
 7         user_type = request.user.user_type
 8         print(user_type)
 9         if user_type == 1:
10             return True
11         else:
12             return False
13 class Course(APIView):
14     authentication_classes = [TokenAuth, ]
15     permission_classes = [UserPermission,]
16 
17     def get(self, request):
18         return HttpResponse('get')
19 
20     def post(self, request):
21         return HttpResponse('post')
View Code

    局部使用只需要在视图类里加入:

     permission_classes = [UserPermission,] 

  • 全局使用

REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}
  • 源码分析

1 def check_permissions(self, request):
2     for permission in self.get_permissions():
3         if not permission.has_permission(request, self):
4             self.permission_denied(
5                 request, message=getattr(permission, 'message', None)
6                 )
View Code

self.get_permissions()

def get_permissions(self):return [permission() for permission in self.permission_classes]

权限类使用顺序:先用视图类中的权限类,再用settings里配置的权限类,最后用默认的权限类

 

六、频率组件

  • 频率简介

      为了控制用户对某个url请求的频率,比如,一分钟以内,只能访问三次

 

  • 自定义频率类,自定义频率规则

    自定义的逻辑:

#(1)取出访问者ip
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
# (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败

    代码实现:

 1 class MyThrottles():
 2     VISIT_RECORD = {}
 3     def __init__(self):
 4         self.history=None
 5     def allow_request(self,request, view):
 6         #(1)取出访问者ip
 7         # print(request.META)
 8         ip=request.META.get('REMOTE_ADDR')
 9         import time
10         ctime=time.time()
11         # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
12         if ip not in self.VISIT_RECORD:
13             self.VISIT_RECORD[ip]=[ctime,]
14             return True
15         self.history=self.VISIT_RECORD.get(ip)
16         # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
17         while self.history and ctime-self.history[-1]>60:
18             self.history.pop()
19         # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
20         # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
21         if len(self.history)<3:
22             self.history.insert(0,ctime)
23             return True
24         else:
25             return False
26     def wait(self):
27         import time
28         ctime=time.time()
29         return 60-(ctime-self.history[-1])
View Code

 

  • 内置频率类及局部使用

      写一个类,继承自SimpleRateThrottle,(根据ip限制)问:要根据用户现在怎么写

1 from rest_framework.throttling import SimpleRateThrottle
2 class VisitThrottle(SimpleRateThrottle):
3     scope = 'luffy'
4     def get_cache_key(self, request, view):
5         return self.get_ident(request)

      在setting里配置:(一分钟访问三次)

1 REST_FRAMEWORK = {
2     'DEFAULT_THROTTLE_RATES':{
3         'luffy':'3/m'
4     }
5 }

      在视图类里使用

throttle_classes = [MyThrottles,]

      错误信息的中文提示:

 1 class Course(APIView):
 2     authentication_classes = [TokenAuth, ]
 3     permission_classes = [UserPermission, ]
 4     throttle_classes = [MyThrottles,]
 5 
 6     def get(self, request):
 7         return HttpResponse('get')
 8 
 9     def post(self, request):
10         return HttpResponse('post')
11     def throttled(self, request, wait):
12         from rest_framework.exceptions import Throttled
13         class MyThrottled(Throttled):
14             default_detail = '傻逼啊'
15             extra_detail_singular = '还有 {wait} second.'
16             extra_detail_plural = '出了 {wait} seconds.'
17         raise MyThrottled(wait)
View Code

      内置频率限制类:

    

    BaseThrottle是所有类的基类:方法:def get_ident(self, request)获取标识,其实就是获取ip,自定义的需要继承它

    AnonRateThrottle:未登录用户ip限制,需要配合auth模块用

    SimpleRateThrottle:重写此方法,可以实现频率现在,不需要咱们手写上面自定义的逻辑

    UserRateThrottle:登录用户频率限制,这个得配合auth模块来用

    ScopedRateThrottle:应用在局部视图上的(忽略)

 

  • 内置频率类及全局使用

REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES':['app01.utils.VisitThrottle',],'DEFAULT_THROTTLE_RATES':{'luffy':'3/m'}
}

 

  • 源码分析

    省略。。。。。。

 

 

七、分页器组件

  • 简单分页(查看第n页,每页显示n条)

 1 from rest_framework.pagination import PageNumberPagination
 2 # 一 基本使用:url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size无效
 3 class  Pager(APIView):
 4     def get(self,request,*args,**kwargs):
 5         # 获取所有数据
 6         ret=models.Book.objects.all()
 7         # 创建分页对象
 8         page=PageNumberPagination()
 9         # 在数据库中获取分页的数据
10         page_list=page.paginate_queryset(ret,request,view=self)
11         # 对分页进行序列化
12         ser=BookSerializer1(instance=page_list,many=True)
13         return Response(ser.data)
14 # 二 自定制 url=http://127.0.0.1:8000/pager/?page=2&size=3
15 # size=30,无效,最多5条
16 class Mypage(PageNumberPagination):
17     page_size = 2
18     page_query_param = 'page'
19     # 定制传参
20     page_size_query_param = 'size'
21     # 最大一页的数据
22     max_page_size = 5
23 class  Pager(APIView):
24     def get(self,request,*args,**kwargs):
25         # 获取所有数据
26         ret=models.Book.objects.all()
27         # 创建分页对象
28         page=Mypage()
29         # 在数据库中获取分页的数据
30         page_list=page.paginate_queryset(ret,request,view=self)
31         # 对分页进行序列化
32         ser=BookSerializer1(instance=page_list,many=True)
33         # return Response(ser.data)
34         # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
35         return page.get_paginated_response(ser.data)

setting中配置:

REST_FRAMEWORK = {# 每页显示两条'PAGE_SIZE':2
}

 路由: url(r'^pager/$', views.Pager.as_view()), 

新建类: Serializers

1 class BookSerializer1(serializers.ModelSerializer):
2     class Meta:
3         model=models.Book
4         # fields="__all__"
5         exclude=('authors',)
  • 偏移分页(在第n个位置,向后查看n条数据)

 1 # http://127.0.0.1:8000/pager/?offset=4&limit=3
 2 from rest_framework.pagination import LimitOffsetPagination
 3 # 也可以自定制,同简单分页
 4 class  Pager(APIView):
 5     def get(self,request,*args,**kwargs):
 6         # 获取所有数据
 7         ret=models.Book.objects.all()
 8         # 创建分页对象
 9         page=LimitOffsetPagination()
10         # 在数据库中获取分页的数据
11         page_list=page.paginate_queryset(ret,request,view=self)
12         # 对分页进行序列化
13         ser=BookSerializer1(instance=page_list,many=True)
14         # return page.get_paginated_response(ser.data)
15         return Response(ser.data)
  • CursorPagination(加密分页,只能看上一页和下一页,速度快)

 1 from rest_framework.pagination import CursorPagination
 2 # 看源码,是通过sql查询,大于id和小于id
 3 class  Pager(APIView):
 4     def get(self,request,*args,**kwargs):
 5         # 获取所有数据
 6         ret=models.Book.objects.all()
 7         # 创建分页对象
 8         page=CursorPagination()
 9         page.ordering='nid'
10         # 在数据库中获取分页的数据
11         page_list=page.paginate_queryset(ret,request,view=self)
12         # 对分页进行序列化
13         ser=BookSerializer1(instance=page_list,many=True)
14         # 可以避免页码被猜到
15         return page.get_paginated_response(ser.data)

 

 

转载于:https://www.cnblogs.com/child-king/p/10456641.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/425524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[剑指offer][JAVA]面试题第[26]题[树的子结构][递归]

【问题描述】[中等] 输入两棵二叉树A和B&#xff0c;判断B是不是A的子结构。(约定空树不是任意一个树的子结构)B是A的子结构&#xff0c; 即 A中有出现和B相同的结构和节点值。例如: 给定的树 A:3/ \4 5/ \1 2 给定的树 B&#xff1a;4 /1 返回 true&#xff0c;因为 B 与…

二分图最大匹配的König定理及其证明

出处:http://www.matrix67.com/blog/archives/116 二分图最大匹配的Knig定理及其证明 如果你看不清楚第二个字母&#xff0c;下面有一个大号字体版本&#xff1a; 二分图最大匹配的Knig定理及其证明 本文将是这一系列里最短的一篇&#xff0c;因为我只打算把Knig定理证了…

【插件介绍】Lombok

Lombok ​ Lombok项目是一个Java库&#xff0c;它会自动插入编辑器和构建工具中&#xff0c;Lombok提供了一组有用的注释&#xff0c;用来消除Java类中的大量样板代码。仅五个字符(Data)就可以替换数百行代码从而产生干净&#xff0c;简洁且易于维护的Java类。 使用步骤&…

图像增强概述

问题背景&#xff08;Background&#xff09; 曝光不足或过度的照片-需要增强处理 图像Fourier频谱看不清-需要增强处理 图像有雾-需要 增强处理 车牌识别系统 车牌识别预处理-车牌图像需要增强处理 人脸识别预处理-人脸图像需要增强处理 指纹识别预处理-指纹图像需要增强处理…

并查集入门

quick-find 时间复杂度 quick-union quick-find&#xfffc;时间复杂度&#xfffc;### quick-union&#xfffc; &#xfffc; 按SIZE合并 按秩合并 路径压缩 面试了解基本思想 做蓝色 写路径隔代压缩 转载链&#xff1a;https://liweiwei1419.gitee.io/leetcode-algo/

Java学习笔记10-2——MyBatis

文章目录MyBatis详细执行流程使用注解开发面向接口开发使用注解开发复杂查询多对一问题测试环境搭建按照查询嵌套处理&#xff08;子查询、嵌套查询&#xff09;按照结果查询&#xff08;联表查询、联合查询&#xff09;一对多问题环境搭建按照结果查询&#xff08;联表查询、联…

基于直方图处理的图像增强

灰度图像的直方图 •灰度级直方图是图像的一种统计表达&#xff0c;它反映了该图中 不同灰度级出现的统计概率。 •设图像具有L个灰度级&#xff0c;图像中像素点的个数为n&#xff0c;它 的第k个灰度级出现的次数为(k0,1,2,…,L-1) 通过直方图可以看出图像整体的性质 直方图…

[Leedcode][JAVA][第1014题][最佳观光组合][数组][暴力优化]

【问题描述】[中等] 给定正整数数组 A&#xff0c;A[i] 表示第 i 个观光景点的评分&#xff0c;并且两个景点 i 和 j 之间的距离为 j - i。一对景点&#xff08;i < j&#xff09;组成的观光组合的得分为&#xff08;A[i] A[j] i - j&#xff09;&#xff1a;景点的评分之…

NLayerAppV3--.net Core2实现的DDD分层架构

虽然每天的工作都是CURD、还是使用着传统的三层架构、使用着.net Framework&#xff0c;但是这并不能影响我学习DDD和.net core。 总是希望软件在应对复杂多变的场景时能够游刃有余&#xff0c;在解决问题时能够多一种选择。 很早就有关注大神dax.net的NLayerApp系列博文https:…

Java学习笔记11-1——Spring5

文章目录1.简介组成拓展2.控制反转&#xff08;IoC&#xff09;IoC例子IoC本质3.Hello&#xff0c;Springdemo1修改user例子的代码思考4.IoC创建对象的方式通过无参构造的方式通过有参构造的方式5.Spring配置alias 设置别名Bean的配置import6.依赖注入&#xff08;DI&#xff0…

空间滤波增强

基本概念 空间域滤波增强采用模板处理方法对图像进行 滤波&#xff0c;去除图像噪声或增强图像的细节 空间域平滑滤波器 分析&#xff1a;任何一幅原始图像&#xff0c;在其获取和传输等过程中&#xff0c; 会受到各种噪声的干扰&#xff0c;使图像模糊&#xff0c;对图像分析…

[剑指offer][JAVA]面试题第[27]题[二叉树的镜像][递归][栈]

【问题描述】[中等] 请完成一个函数&#xff0c;输入一个二叉树&#xff0c;该函数输出它的镜像。例如输入&#xff1a;4/ \2 7/ \ / \ 1 3 6 9 镜像输出&#xff1a;4/ \7 2/ \ / \ 9 6 3 1示例 1&#xff1a;输入&#xff1a;root [4,2,7,1,3,6,9]…

瓶颈分析

Top指令&#xff1a; CPU/内存情况 top # top指令可以显示总体CPU占用率、内存使用率和交换情况&#xff0c;以及所有进程对应的CPU、内存占用情况 终端下使用该指令示例结果&#xff1a; 上图对一些重要的参数进行了简单标识&#xff0c;笔者这里使用的是XShell对远程Linux服务…

Java学习笔记11-2——Spring5

文章目录7.Bean的自动装配自动装配说明测试环境搭建byName&#xff08;按名称自动装配&#xff09;测试byName运行机制小结&#xff1a;byType&#xff08;按类型自动装配&#xff09;测试使用注解进行自动装配AutowiredQualifierResourceAutowired与Resource异同8.使用注解开发…

频率域平滑滤波器

频率域滤波增强方法 理想低通滤波器 理想低通滤波器(Ideal Lowpass Filters-ILPF) 尽管理想低通滤波器在数学上定义清楚&#xff0c;在计算机模拟中也可 实现&#xff0c;但在截止频率处直上直下的理想低通滤波器是不能用实际的 电子器件实现的。 理想滤波器有陡峭频率的截止…

[leetcode][JAVA]面试题第[1028]题[迭代]

【问题描述】[困难] 我们从二叉树的根节点 root 开始进行深度优先搜索。 在遍历中的每个节点处&#xff0c;我们输出 D 条短划线&#xff08;其中 D 是该节点的深度&#xff09;&#xff0c;然后输出该节点的值。&#xff08;如果节点的深度为 D&#xff0c;则其直接子节点的…

频率域锐化滤波器

频率域锐化滤波器 &#xff08;Frequency Sharpening Filters &#xff09; 图像的边缘、细节主要位于高频部分&#xff0c;而图 像的模糊是由于高频成分比较弱产生的。 频率域锐化就是为了消除模糊&#xff0c;突出边缘。 采用高通滤波器让高频成分通过&#xff0c;使低频成 …

6用NetBeans进行JSP开发

用NetBeans进行JSP开发 NetBeans

Java学习笔记12——JVM入门

文章目录JVM简介和体系结构JVM的位置JVM的体系结构类加载器双亲委派机制沙箱安全机制&#xff08;了解即可&#xff09;NativePC寄存器方法区栈三种JVM堆新生区永久区堆内存调优Jprofiler的使用GC&#xff08;垃圾回收&#xff09;引用计数法复制算法标记清除法标记压缩法GC算法…