日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Rest Framework

發布時間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

總結

以上是生活随笔為你收集整理的Rest Framework的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。