目录导航

  一、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

Rest Framework相关推荐

  1. Tengine Framework基础

    Tengine Framework基础 最受开发者喜爱的边缘AI计算框架 Tengine是OPEN AI LAB推出的自主知识产权的边缘AI计算框架,致力于解决AIoT产业链碎片化问题,加速AI产业化 ...

  2. EF-Entity Framework 相关技术点收集贴

    不定期.偶尔.添加更新 在网络上看到或者自己开发过程中碰到的EF-Entity Framework相关技术点 本文地址:http://www.cnblogs.com/vnii/archive/2012 ...

  3. Qt Installer Framework实战

    Qt Installer Framework是Qt发布的安装程序支持框架,只需要简单的配置就可以生成安装文件,同时可以通过javascript脚本来定制安装过程. 目录结构 config packag ...

  4. 在虚拟机中 windows 2003 装.net framework 3.5 出现问题.

    错误信息: [11/27/09,08:52:50] Microsoft .NET Framework 2.0a: [2] Error: Installation failed for componen ...

  5. .Net Framework 3.0 概述

    Microsoft .NET Framework 3.0, the managed programming model for Microsoft® Windows®, includes the .N ...

  6. MIS开发中.net Framework的打印功能

    Microsoft .net Framework的打印功能都以组件的方式提供,为程序员提供了很大的方便,但是这几个组件的使用还是很复杂的,有必要解释一下. 打印操作通常包括以下四个功能 1 打印设置 ...

  7. python导入matplotlib出错_解决导入matplotlib的RuntimeError: Python is not installed as a framework....

    import matplotlib.pyplot as plt 报错: RuntimeError: Python is not installed as a framework. The Mac OS ...

  8. ios Standard Framework和Umbrella Framework

    Standard Framework:标准库,通过引用对应的header文件而不是引用master header 文件来引用类(也可以通过引用Master Header file来引用需要使用的类), ...

  9. ios .framework动态库重签名

    真机上运行.framework时,如果报 dyld'dyld_fatal_error:dyld: Library not loaded: @rpath/XX.framework/XXReference ...

  10. ios .a和.framework

    创建Aggregate来合并模拟器和真机通用的framework 然后在Build Phases下New Run Script Phase创建合并脚本: # Constants SF_TARGET_N ...

最新文章

  1. 引燃AI社区,不用跨界也能从文本生成图像,OpenAI新模型打破自然语言与视觉次元壁...
  2. SpringCloud 分布式事务解决方案
  3. 拉力赛 (Standard IO)
  4. mysql双机数据热备份_如何设置MySql数据同步实现双机热备份
  5. 黑马程序员C语言基础(第六天)指针
  6. SpringBoot 配置Tomcat运行
  7. java之代理设计模式
  8. 2014 年度 Git@OSC 最热门的 50 个项目
  9. [刷题]算法竞赛入门经典(第2版) 5-2/UVa1594 - Ducci Sequence
  10. SCPPO(十一):网站发布中的问题锦集—ReportViewer版本问题
  11. Android 动画
  12. java语言英语单词_Java常用英语单词
  13. Android Display ID 对应关系
  14. 再见python你好julia_再见 Python 2,你好 Python 3
  15. 多模块项目-项目复制出现Module xx must not contain source root xx The root already belongs to module xx
  16. 会计凭证替代BTE增强
  17. jQuery遍历对象、数组、集合
  18. markdown转VNode
  19. 彻底删除MySQL57服务
  20. 关于SG/SP, GG/GP的一点个人理解

热门文章

  1. 实例8:python
  2. python网格划分_在python中创建一个2d网格
  3. 做系统ghost步骤图解_用好这工具,小孩都能会重装系统!
  4. windows下启动activemq闪退
  5. 碎片脚本注解(后续整理)
  6. HDU 6064 RXD and numbers
  7. 使用java修改图片DPI
  8. UML九种图 之 包图和对象图
  9. 思维探索者:从问题到答案的思维过程 像侦探一样思考
  10. [Cocoa]深入浅出Cocoa之Core Data(2)- 手动编写代码