定義:url惟必定位資源,http請求方式區分用戶行爲前端
(1)接口設計規範正則表達式
(2)返回數據規範算法
(3)錯誤消息規範數據庫
下載:pip install djangorestframeworkdjango
引入:from rest_framework import APIView編程
APIView的原碼:json
可以發各類方式的請求並對請求頭的數據進行修改且對結果進行格式化的工具 api
解析器:Django只能解析urlencoded格式的數據,經過解析器 能夠解析各類數據類型(json)的數據瀏覽器
(1)使用方式restful
導入模塊
1 from rest_framework.views import APIView
(2)繼承
(3)
(4)使用
原碼:
APIView中的
0.原始序列化方法
model對象=>字典
from django.forms.models import model_to_dict
model_to_dict方法:將model對象轉換成字典
0.djaogo的自帶的序列化方法
from django.core import serializers
ret=serializers.serialize("json",queryset)
獲得的ret就是序列化後的結果
(1)Serializer,相似於Form
1 #1.導入模塊 2 from rest_framework.views import APIView 3 from rest_framework import serializers 4 #使返回的數據可以格式化 5 #瀏覽器上也可以使用rest_framework組件 6 #***前提是settings中的INSTALLED_APPS要配置該組件*** 7 from rest_framework.response import Response 8 9 from django.shortcuts import HttpResponse 10 from app01.models import * 11 12 #2.寫一個類繼承serializers.Serializer 13 class BookSerializer(serializers.Serializer): 14 title=serializers.CharField(max_length=32) 15 price=serializers.CharField(max_length=32) 16 #對於一對多的字段,用source來決定返回給前端的內容 17 publish=serializers.CharField(source="publish.name") 18 #對於多對多的字段,用鉤子函數來編輯返回給前端的內容 19 authors=serializers.SerializerMethodField() 20 #鉤子函數的名字是get+字段的名字 21 def get_authors(self,book_obj): 22 s="" 23 for obj in book_obj.authors.all(): 24 s=s+obj.name 25 return s 26 27 class BookView(APIView): 28 def get(self,request): 29 book_list=Book.objects.all() 30 #多個對象時 31 #many爲True表示多個對象,默認爲false,位false時能夠省略不寫 32 bs=BookSerializer(book_list,many=True) 33 #單個對象時 34 #bs=BookSerializer(book_obj) 35 return Response(bs.data) # 返回的是[{},{}]的形式
因爲使用的是Response返回的數據,訪問該路徑時,可以獲得rest_framework組件爲咱們提供的頁面
在訪問的路徑後加上?format=json,獲得的是數據部分
(2)ModelSerializer,相似於ModelForm
1 #1.導入模塊 2 from rest_framework.views import APIView 3 from rest_framework import serializers 4 #使返回的數據可以格式化 5 #瀏覽器上也可以使用rest_framework組件 6 #***前提是settings中的INSTALLED_APPS要配置該組件*** 7 from rest_framework.response import Response 8 9 from django.shortcuts import HttpResponse 10 from app01.models import * 11 12 #2.寫一個類繼承serializers.ModelSerializer 13 class BookModelSerializer(serializers.ModelSerializer): 14 class Meta: 15 model=Book 16 fields="__all__" 17 #自定義的字段 18 publish=serializers.CharField(source="publish.name") 19 authors=serializers.SerializerMethodField() 20 def get_authors(self,book_obj): 21 s="" 22 for obj in book_obj.authors.all(): 23 s=s+obj.name 24 return s 25 26 class BookView(APIView): 27 def get(self,request): 28 book_list=Book.objects.all() 29 #多個對象時 30 #many爲True表示多個對象,默認爲false,位false時能夠省略不寫 31 bs=BookModelSerializer(book_list,many=True) 32 #單個對象時 33 #bs=BookSerializer(book_obj) 34 return Response(bs.data) # 返回的是[{},{}]的形式
訪問時獲得的頁面
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 #使返回的數據可以格式化 6 #瀏覽器上也可以使用rest_framework組件 7 #前提是settings中的INSTALLED_APPS要配置該組件 8 from rest_framework.response import Response 9 10 #1.編寫繼承ModelSerializer的類 11 class BookModelSerializer(serializers.ModelSerializer): 12 class Meta: 13 model=Book 14 fields="__all__" 15 publish=serializers.CharField(source="publish.pk") 16 # authors=serializers.SerializerMethodField() 17 18 def get_authors(self,book_obj): 19 s="" 20 for obj in book_obj.authors.all(): 21 s=s+obj.name 22 return s 23 #2.對於一對多的字段,ModelSerializer中的create方法不支持source,重寫create方法 24 def create(self,validated_data): 25 book_obj=Book.objects.create(title=validated_data["title"],price=validated_data["price"],publish_id=validated_data["publish"]["pk"]) 26 book_obj.authors.add(*validated_data["authors"]) 27 return book_obj 28 29 class BookView(APIView): 30 def post(self,request): 31 bs=BookModelSerializer(data=request.data) 32 #3.經過實例對象的is_valid()方法,對請求數據的合法性進行校驗,有instance就是update,沒有就是create 33 if bs.is_valid(): 34 #4.調用save()方法,將數據插入數據庫 35 #會執行create方法 36 bs.save() 37 return Response(bs.data) 38 else: 39 #5.數據不合格返回錯誤信息 40 return Response(bs.errors)
(1)url設計
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path('book/$', views.BookView.as_view()), 4 re_path('book/(\d+)/$', views.BookDetailView.as_view()), 5 ]
(2)視圖設計
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from rest_framework.response import Response 6 7 class BookModelSerializer(serializers.ModelSerializer): 8 class Meta: 9 model=Book 10 fields="__all__" 11 publish=serializers.CharField(source="publish.pk") 12 # authors=serializers.SerializerMethodField() 13 14 def get_authors(self,book_obj): 15 s="" 16 for obj in book_obj.authors.all(): 17 s=s+obj.name 18 return s 19 def create(self,validated_data): 20 book_obj=Book.objects.create(title=validated_data["title"],price=validated_data["price"],publish_id=validated_data["publish"]["pk"]) 21 book_obj.authors.add(*validated_data["authors"]) 22 return book_obj 23 24 class BookDetailView(APIView): 25 def get(self,request,id): 26 book=Book.objects.filter(pk=id).first() 27 bs=BookModelSerializer(book) 28 return Response(bs.data)
(3)返回數據
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from rest_framework.response import Response 6 7 class BookModelSerializer(serializers.ModelSerializer): 8 class Meta: 9 model=Book 10 fields="__all__" 11 12 class BookDetailView(APIView): 13 def put(self,request,id): 14 book = Book.objects.filter(pk=id).first() 15 bs=BookModelSerializer(book,data=request.data) 16 if bs.is_valid(): 17 #此時執行的不是create方法,是update方法 18 bs.save() 19 return Response(bs.data) 20 else: 21 return Response(bs.errors)
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from rest_framework.response import Response 6 7 class BookModelSerializer(serializers.ModelSerializer): 8 class Meta: 9 model=Book 10 fields="__all__" 11 12 class BookDetailView(APIView): 13 def delete(self,request,id): 14 Book.objects.filter(pk=id).delete() 15 return Response()
實現效果:
創建向Book表的BookView,BookDetailView同樣的Publish表的兩個視圖類
1 class PublishView(APIView): 2 def get(self,request): 3 book_list=Publish.objects.all() 4 print(book_list) 5 bs=PublishModelSerializer(book_list,many=True) 6 print(bs) 7 print(bs.data) 8 return Response(bs.data) # [{},{}]的形式 9 def post(self,request): 10 print(request.data) bs=PublishModelSerializer(data=request.data) 11 if bs.is_valid(): 12 #會執行create方法 13 print(111) 14 bs.save() 15 print(bs.data) 16 return Response(bs.data) 17 else: 18 return Response(bs.errors) 19 class PublishDetailView(APIView): 20 def get(self,request,id): 21 book=Publish.objects.filter(pk=id).first() 22 bs=PublishModelSerializer(book) 23 print(book) 24 print(bs) 25 print('-------',bs.data) 26 return Response(bs.data) 27 28 def put(self,request,id): 29 book = Publish.objects.filter(pk=id).first() 30 bs=PublishModelSerializer(book,data=request.data) 31 if bs.is_valid(): 32 bs.save() 33 return Response(bs.data) 34 else: 35 return Response(bs.errors) 36 37 def delete(self,request,id): 38 Publish.objects.filter(pk=id).delete() 39 return Response()
視圖類中須要的PublishModelSerializer
1 class PublishModelSerializer(serializers.ModelSerializer): 2 class Meta: 3 model=Publish 4 fields="__all__"
修改訪問BookView時的publish的顯示方式
1 class BookModelSerializer(serializers.ModelSerializer): 2 class Meta: 3 model=Book 4 fields="__all__" 5 publish=serializers.HyperlinkedIdentityField( 6 view_name="publish_detail",#路徑的別名 7 lookup_field="publish_id", 8 lookup_url_kwarg="id"#路徑中用到的動態匹配的數據 9 )
設置BookModelSerializer須要的view_name,lookup_url_kwarg
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 # path('publish/', views.PublishView.as_view()), 4 path('publishnew/', views.PublishnNewView.as_view(),name="publishnew"), 5 re_path('book/$', views.BookView.as_view(),name="book"), 6 re_path('publish/$', views.PublishView.as_view(),name="publish"), 7 re_path('book/(\d+)/$', views.BookDetailView.as_view(),name="bookdetail"), 8 re_path('publish/(?P<id>\d+)/$', views.PublishDetailView.as_view(),name="publish_detail"), 9 ]
用了Hyperlinked,之後調用時,都要加上context={'request': request}
1 CreateModelMixin 添加 2 DestroyModelMixin 刪除 3 ListModelMixin 查多個 4 RetrieveModelMixin 查單個 5 UpdateModelMixin 更新
ListModelMixin部分原碼
1 class ListModelMixin(object): 2 """ 3 List a queryset. 4 """ 5 def list(self, request, *args, **kwargs): 6 #獲取queryset 7 queryset = self.filter_queryset(self.get_queryset()) 8 9 page = self.paginate_queryset(queryset) 10 if page is not None: 11 serializer = self.get_serializer(page, many=True) 12 return self.get_paginated_response(serializer.data) 13 #序列化 14 serializer = self.get_serializer(queryset, many=True) 15 #返回.data數據 16 return Response(serializer.data)
CreateModelMixin部分原碼
1 class ListModelMixin(object): 2 """ 3 List a queryset. 4 """ 5 def list(self, request, *args, **kwargs): 6 #獲取queryset 7 queryset = self.filter_queryset(self.get_queryset()) 8 9 page = self.paginate_queryset(queryset) 10 if page is not None: 11 serializer = self.get_serializer(page, many=True) 12 return self.get_paginated_response(serializer.data) 13 #序列化 14 serializer = self.get_serializer(queryset, many=True) 15 #返回.data數據 16 return Response(serializer.data)
CreateModelMixin部分原碼
1 class CreateModelMixin(object): 2 """ 3 Create a model instance. 4 """ 5 def create(self, request, *args, **kwargs): 6 #獲取ModelSerializer的實例對象 7 serializer = self.get_serializer(data=request.data) 8 #判斷是否合法,成功了繼續走,錯誤了拋錯 9 serializer.is_valid(raise_exception=True) 10 #合法後執行save方法 11 self.perform_create(serializer) 12 headers = self.get_success_headers(serializer.data) 13 return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 14 15 def perform_create(self, serializer): 16 serializer.save() 17 18 def get_success_headers(self, data): 19 try: 20 return {'Location': str(data[api_settings.URL_FIELD_NAME])} 21 except (TypeError, KeyError): 22 return {}
使用
在urls.py中
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path('author/$', views.AuthorView.as_view(),name="author"), 4 #***此處正則表達式的有名分組必定要命名爲pk*** 5 re_path('author/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(),name="author_detail"), 6 ]
在視圖中
1 #1.導入須要的類 2 from rest_framework import mixins 3 from rest_framework import generics 4 5 #GenericAPIView繼承了APIView 6 #定義的類除了要繼承mixins下的類之外,還要繼承GenericAPIView類 7 class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView): 8 #如下兩個配置信息的名字是固定的 9 #queryset這次表示處理的數據 10 queryset=Author.objects.all() 11 #serializers表示用到的序列化組件 12 serializer_class=AuthorModelSerializer 13 def get(self, request, *args, **kwargs): 14 #ListModelMixin類中的方法 15 return self.list(self, request, *args, **kwargs) 16 def post(self, request, *args, **kwargs): 17 #CreateModelMixin中的方法 18 return self.create(self, request, *args, **kwargs) 19 20 class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView): 21 queryset = Author.objects.all() 22 serializer_class = AuthorModelSerializer 23 def get(self, request,pk, *args, **kwargs): 24 return self.retrieve(self, request,pk, *args, **kwargs) 25 def put(self, request,id, *args, **kwargs): 26 return self.update(self, request,id, *args, **kwargs) 27 def delete(self, request,id, *args, **kwargs): 28 return self.destroy(self, request,id, *args, **kwargs)
get請求獲得的數據
1 [ 2 { 3 "nid": 1, 4 "name": "徐志摩", 5 "age": 25 6 }, 7 { 8 "nid": 2, 9 "name": "魯迅", 10 "age": 25 11 } 12 ]
ListCreateAPIView原碼部分
1 ##ListCreateAPIView固定繼承了mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView 2 class ListCreateAPIView(mixins.ListModelMixin, 3 mixins.CreateModelMixin, 4 GenericAPIView): 5 #貼心到連get和post方法都寫了 6 def get(self, request, *args, **kwargs): 7 return self.list(request, *args, **kwargs) 8 9 def post(self, request, *args, **kwargs): 10 return self.create(request, *args, **kwargs)
RetrieveUpdateDestroyAPIView原碼部分(與ListCreateAPIView原理相同)
1 class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, 2 mixins.UpdateModelMixin, 3 mixins.DestroyModelMixin, 4 GenericAPIView): 5 6 def get(self, request, *args, **kwargs): 7 return self.retrieve(request, *args, **kwargs) 8 9 def put(self, request, *args, **kwargs): 10 return self.update(request, *args, **kwargs) 11 12 def patch(self, request, *args, **kwargs): 13 return self.partial_update(request, *args, **kwargs) 14 15 def delete(self, request, *args, **kwargs): 16 return self.destroy(request, *args, **kwargs)
使用
在urls.py中
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path('author/$', views.AuthorView.as_view(),name="author"), 4 #***此處正則表達式的有名分組必定要命名爲pk*** 5 re_path('author/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(),name="author_detail"), 6 ]
在視圖中
1 from rest_framework import generics 2 3 class AuthorView(generics.ListCreateAPIView): 4 queryset=Author.objects.all() 5 serializer_class=AuthorModelSerializer 6 7 class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView): 8 queryset = Author.objects.all() 9 serializer_class = AuthorModelSerializer
使用
在urls.py中
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 #利用as_view的參數,規定什麼請求方式用什麼方法處理 4 re_path(r'^books/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="book_list"), 5 re_path(r'^books/(?P<pk>\d+)$', views.AuthorViewSet.as_view({ 6 'get': 'retrieve', 7 'put': 'update', 8 'patch': 'partial_update', 9 'delete': 'destroy' 10 }), name="book_detail"), 11 ]
在視圖中
1 from rest_framework import viewsets 2 class AuthorViewSet(viewsets.ModelViewSet): 3 queryset = Book.objects.all() 4 serializer_class = AuthorModelSerializer
(1)定義一個認證類
1 class UserAuth(): 2 #此方法原碼中會用到,必定要寫 3 def authenticate_header(self,request): 4 pass 5 def authenticate(self,request): 6 token=request.GET.get("token") 7 token_obj = UserToken.objects.filter(token=token).first() 8 if not token_obj: 9 raise APIException("驗證失敗!") 10 return (token_obj.user, token_obj)
或者用BaseAuthentication類來代替authenticate_header方法
1 from rest_framework.authentication import BaseAuthentication 2 class UserAuth(BaseAuthentication): 3 def authenticate(self,request): 4 token=request.GET.get("token") 5 token_obj = UserToken.objects.filter(token=token).first() 6 if not token_obj: 7 raise APIException("驗證失敗!") 8 return (token_obj.user, token_obj)
(2)在須要認證的數據接口裏面指定認證類
1 class AuthorViewSet(viewsets.ModelViewSet): 2 ***authentication_classes = [UserAuth,]*** 3 queryset = Author.objects.all() 4 serializer_class = AuthorModelSerializer
(3)前提:要在登陸時注入token
1 def get_random_str(): 2 import uuid 3 random_str=str(uuid.uuid4()).replace("-","") 4 return random_str 5 6 class LoginView(APIView): 7 def post(self,request): 8 user_name=request.data.get("user_name") 9 password=request.data.get("password") 10 user_obj=User.objects.filter(user_name=user_name,password=password).first() 11 res={} 12 if not user_obj: 13 res["state"]=1001 14 res["meg"]='用戶名或祕密錯誤' 15 else: 16 token=get_random_str() 17 print(token) 18 UserToken.objects.update_or_create(user=user_obj, defaults={"token": token}) 19 res["state"]=1000 20 res["meg"]='登陸成功' 21 return JsonResponse(res)
(1)將UserAuth單放在一個文件中
utiles中
1 from app01.models import * 2 from rest_framework.exceptions import APIException 3 class UserAuth(): 4 def authenticate_header(self,request): 5 pass 6 def authenticate(self,request): 7 token=request.GET.get("token") 8 token_obj = UserToken.objects.filter(token=token).first() 9 if not token_obj: 10 raise APIException("驗證失敗!") 11 return (token_obj.user, token_obj)
(2)在配置文件中添加配置
1 REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":("app01.utiles.UserAuth",) 3 }
class APIView(View):
1 #***1執行as_view方法 2 def as_view(cls, **initkwargs): 3 if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): 4 def force_evaluation(): 5 raise RuntimeError( 6 'Do not evaluate the `.queryset` attribute directly, ' 7 'as the result will be cached and reused between requests. ' 8 'Use `.all()` or call `.get_queryset()` instead.' 9 ) 10 cls.queryset._fetch_all = force_evaluation 11 #***2.繼承父類的as_view方法並執行 12 view = super(APIView, cls).as_view(**initkwargs) 13 view.cls = cls 14 view.initkwargs = initkwargs 15 return csrf_exempt(view) 16 17 ########################################################### 18 19 #***3.續 20 def dispatch(self, request, *args, **kwargs): 21 """ 22 `.dispatch()` is pretty much the same as Django's regular dispatch, 23 but with extra hooks for startup, finalize, and exception handling. 24 """ 25 self.args = args 26 self.kwargs = kwargs 27 #***4.執行initialize_request方法 28 request = self.initialize_request(request, *args, **kwargs) 29 self.request = request 30 self.headers = self.default_response_headers # deprecate? 31 32 try: 33 #***8.執行inital方法 34 self.initial(request, *args, **kwargs) 35 36 # Get the appropriate handler method 37 if request.method.lower() in self.http_method_names: 38 handler = getattr(self, request.method.lower(), 39 self.http_method_not_allowed) 40 else: 41 handler = self.http_method_not_allowed 42 43 response = handler(request, *args, **kwargs) 44 45 except Exception as exc: 46 response = self.handle_exception(exc) 47 48 self.response = self.finalize_response(request, response, *args, **kwargs) 49 return self.response 50 51 ########################################################### 52 53 #***4.續 54 def initialize_request(self, request, *args, **kwargs): 55 """ 56 Returns the initial request object. 57 """ 58 parser_context = self.get_parser_context(request) 59 #***5.實例化Request對象 60 return Request( 61 request, 62 parsers=self.get_parsers(), 63 #***6.執行get_authenticators方法 64 authenticators=self.get_authenticators(), 65 negotiator=self.get_content_negotiator(), 66 parser_context=parser_context 67 ) 68 69 ########################################################### 70 #***6.續 71 def get_authenticators(self): 72 #***7.authentication_classes爲自定義的類中的字段:[UserAuth,] 73 return [auth() for auth in self.authentication_classes] 74 75 ########################################################### 76 #***8.續 77 def initial(self, request, *args, **kwargs): 78 self.format_kwarg = self.get_format_suffix(**kwargs) 79 neg = self.perform_content_negotiation(request) 80 request.accepted_renderer, request.accepted_media_type = neg 81 82 version, scheme = self.determine_version(request, *args, **kwargs) 83 request.version, request.versioning_scheme = version, scheme 84 #***9.用戶認證方法 85 self.perform_authentication(request) 86 self.check_permissions(request) 87 self.check_throttles(request) 88 89 ########################################################### 90 91 #***9.續 92 def perform_authentication(self, request): 93 #***10.執行Request類下的user方法 94 request.user
class View:
1 def as_view(cls, **initkwargs): 2 3 for key in initkwargs: 4 if key in cls.http_method_names: 5 raise TypeError("You tried to pass in the %s method name as a " 6 "keyword argument to %s(). Don't do that." 7 % (key, cls.__name__)) 8 if not hasattr(cls, key): 9 raise TypeError("%s() received an invalid keyword %r. as_view " 10 "only accepts arguments that are already " 11 "attributes of the class." % (cls.__name__, key)) 12 13 def view(request, *args, **kwargs): 14 self = cls(**initkwargs) 15 if hasattr(self, 'get') and not hasattr(self, 'head'): 16 self.head = self.get 17 self.request = request 18 self.args = args 19 self.kwargs = kwargs 20 #***3.執行APIView中的dispatch方法 21 return self.dispatch(request, *args, **kwargs) 22 view.view_class = cls 23 view.view_initkwargs = initkwargs 24 update_wrapper(view, cls, updated=()) 25 update_wrapper(view, cls.dispatch, assigned=()) 26 return view
自定義
1 #***7.續 2 class AuthorViewSet(viewsets.ModelViewSet): 3 authentication_classes = [UserAuth,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
Request
1 #***10.續 2 def user(self): 3 if not hasattr(self, '_user'): 4 with wrap_attributeerrors(): 5 #***11.執行_authenticate方法 6 self._authenticate() 7 #***15.返回14步驟的當前登陸對象 8 return self._user 9 10 ############################################################# 11 12 #***11.續 13 def _authenticate(self): 14 #***12.self.authenticators爲7步驟的結果[UserAuth(),] 15 for authenticator in self.authenticators: 16 try: 17 #***13.執行自定義的認證類下的authenticate方法 18 user_auth_tuple = authenticator.authenticate(self) 19 #***14.續 20 #若是用戶的token值錯誤拋錯,在此拋錯 21 except exceptions.APIException: 22 self._not_authenticated() 23 raise 24 25 if user_auth_tuple is not None: 26 self._authenticator = authenticator 27 #若是用戶的token值正確, self.user爲當前登陸對象 28 self.user, self.auth = user_auth_tuple 29 return 30 31 self._not_authenticated()
class UserAuth():
1 def authenticate_header(self,request): 2 pass 3 #***13.續 4 def authenticate(self,request): 5 token=request.GET.get("token") 6 token_obj = UserToken.objects.filter(token=token).first() 7 #***14.分狀況討論 8 if not token_obj: 9 #若是用戶的token值錯誤,拋錯 10 raise APIException("驗證失敗!") 11 #若是用戶帶有正確的token值 12 return (token_obj.user, token_obj)
1.一次性從前端獲取多條數據
2.給 name屬性賦值,就會執行 第二個方法
(1)定義權限類
1 class UserPerms(): 2 #方法名稱必定叫has_permission 3 #自定義錯誤信息 4 def has_permission(self,request,view): 5 if request.user.user_type == 3: 6 return True 7 else: 8 return False
(2)指定權限驗證類
1 class AuthorViewSet(viewsets.ModelViewSet): 2 authentication_classes = [UserAuth,] 3 #使用 方式與認證相同 4 permission_classes = [UserPerms,] 5 queryset = Author.objects.all() 6 serializer_class = AuthorModelSerializer
能夠指定多個認證類,若是返回數據,應在最後一個類中返回數據
(3)前提也是登陸時要注入token
1 REST_FRAMEWORK={ 2 "DEFAULT_PERMISSION_CLASSES":["app01.utiles.UserPerms",] 3 }
從APIView的dispatch方法開始剖析
APIView
1 #***1.執行dispatch方法def dispatch(self, request, *args, **kwargs): 2 3 self.args = args 4 self.kwargs = kwargs 5 request = self.initialize_request(request, *args, **kwargs) 6 self.request = request 7 self.headers = self.default_response_headers # deprecate? 8 9 try: 10 #***2.執行initial方法(有續) 11 self.initial(request, *args, **kwargs) 12 13 # Get the appropriate handler method 14 if request.method.lower() in self.http_method_names: 15 handler = getattr(self, request.method.lower(), 16 self.http_method_not_allowed) 17 else: 18 handler = self.http_method_not_allowed 19 20 response = handler(request, *args, **kwargs) 21 22 except Exception as exc: 23 response = self.handle_exception(exc) 24 25 self.response = self.finalize_response(request, response, *args, **kwargs) 26 return self.response 27 28 ##############################################################333# 29 30 #***2.續 31 def initial(self, request, *args, **kwargs): 32 33 self.format_kwarg = self.get_format_suffix(**kwargs) 34 35 # Perform content negotiation and store the accepted info on the request 36 neg = self.perform_content_negotiation(request) 37 request.accepted_renderer, request.accepted_media_type = neg 38 39 # Determine the API version, if versioning is in use. 40 version, scheme = self.determine_version(request, *args, **kwargs) 41 request.version, request.versioning_scheme = version, scheme 42 43 # Ensure that the incoming request is permitted 44 self.perform_authentication(request) 45 #***3.執行check_permissions權限方法(有續) 46 self.check_permissions(request) 47 self.check_throttles(request) 48 49 ###########################################################3 50 51 #***3.續 52 def check_permissions(self, request): 53 #***4.執行self.get_permissions方法(有續) 54 for permission in self.get_permissions(): 55 #***6.執行自定義的has_permission方法 56 if not permission.has_permission(request, self): 57 #***7.執行permission_denied(有續) 58 self.permission_denied( 59 request, message=getattr(permission, 'message', None) 60 ) 61 ######################################################### 62 #***4.續 63 def get_permissions(self): 64 #***5.self.permission_classes位自定義的屬性(有續) 65 return [permission() for permission in self.permission_classes] 66 ######################################################### 67 #***7.續 68 def permission_denied(self, request, message=None): 69 #False拋錯,True無論 70 if request.authenticators and not request.successful_authenticator: 71 raise exceptions.NotAuthenticated() 72 raise exceptions.PermissionDenied(detail=message)
1 class AuthorViewSet(viewsets.ModelViewSet): 2 authentication_classes = [UserAuth,] 3 #***5.續 4 permission_classes = [UserPerms] 5 queryset = Author.objects.all() 6 serializer_class = AuthorModelSerializer
1 class UserPerms(): 2 #***6.續 3 message="您沒有查看該數據的權限" #自定義錯誤信息 4 def has_permission(self,request,view): 5 if request.user.user_type == 3: 6 return True 7 else: 8 return False 9 #符合條件返回True,不符合條件返回False
定義頻率類
1 class VisitRateThrottle(): 2 def allow_request(request,self,view): 3 if 經過: 4 return True#經過 5 else: 6 return False#不經過,頻率超了
指定頻率類
1 class AuthorViewSet(viewsets.ModelViewSet): 2 #指定頻率類 3 throttle_classes = [VisitRateThrottle,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
1 from rest_framework.throttling import BaseThrottle 2 VISIT_RECORD={} 3 class VisitRateThrottle(BaseThrottle): 4 5 def __init__(self): 6 self.history=None 7 #定義頻率類 8 def allow_request(self,request,view): 9 remote_addr = request.META.get('REMOTE_ADDR') 10 print(remote_addr) 11 import time 12 ctime=time.time() 13 14 if remote_addr not in VISIT_RECORD: 15 VISIT_RECORD[remote_addr]=[ctime,] 16 return True 17 18 history=VISIT_RECORD.get(remote_addr) 19 self.history=history 20 21 while history and history[-1]<ctime-60: 22 history.pop() 23 #每分鐘最多訪問幾回 24 if len(history)<3: 25 history.insert(0,ctime) 26 return True 27 else: 28 return False 29 30 def wait(self): 31 import time 32 ctime=time.time() 33 return 60-(ctime-self.history[-1])
1 class AuthorViewSet(viewsets.ModelViewSet): 2 #指定頻率類 3 throttle_classes = [VisitRateThrottle,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
定義頻率類
1 from rest_framework.throttling import SimpleRateThrottle 2 class RateThrottle(SimpleRateThrottle): 3 rate = "5/m" 4 def get_cache_key(self, request, view): 5 return self.get_ident(request)
1 class AuthorViewSet(viewsets.ModelViewSet): 2 #指定頻率類 3 throttle_classes = [RateThrottle,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
定義頻率類
1 from rest_framework.throttling import SimpleRateThrottle 2 class RateThrottle(SimpleRateThrottle): 3 # 指定訪問頻率 4 scope = 'visit_rate' 5 # 指定經過什麼方式來區分用戶 6 def get_cache_key(self, request, view): 7 return self.get_ident(request)
在settings配置文件中
1 REST_FRAMEWORK = { 2 "DEFAULT_THROTTLE_CLASSES": ('app01.throttle.RateThrottle',), 3 "DEFAULT_THROTTLE_RATES": { 4 "visit_rate": "5/m" 5 } 6 }
1 #導入模塊 2 from django.urls import path,re_path,include 3 from app01 import views 4 from rest_framework import routers 5 #生成一個註冊器的實例對象 6 routers=routers.DefaultRouter() 7 #註冊url接口,第一個參數爲路徑部分,第二個參數爲視圖類 8 routers.register(r"author",views.AuthorViewSet)
1 #生成url 2 urlpatterns = [ 3 path('admin/', admin.site.urls), 4 # 5 re_path(r"^",include(routers.urls)) 6 ]
前提:只針對viewsets.ModelViewSet的狀況
1 class AuthorViewSet(viewsets.ModelViewSet): 2 queryset = Author.objects.all() 3 serializer_class = AuthorModelSerializer
1 #引入模塊 2 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer 3 class AuthorViewSet(viewsets.ModelViewSet): 4 #指定 5 renderer_classes = [JSONRenderer,] 6 queryset = Author.objects.all() 7 serializer_class = AuthorModelSerializer 8 pagination_class = MyPagenation
效果:之前瀏覽器在訪問時,會獲得rest_framework爲咱們提供的頁面,
使用JSONRenderer後瀏覽器只能獲得json數據,沒有壓頁面
1 #導入模塊 2 from rest_framework.pagination import PageNumberPagination 3 class BookView(APIView): 4 def get(self,request): 5 #獲取queryset 6 book_list=Book.objects.all() 7 #實例化PageNumberPagination 8 paginater=PageNumberPagination() 9 #調用paginate_queryset方法 10 paged_books=paginater.paginate_queryset(book_list,request,self) 11 #將分頁後的數據傳入BookModelSerializer 12 bs=BookModelSerializer(paged_books,many=True,context={'request': request}) 13 return Response(bs.data)
注意在settings中配置REST_FRAMEWORK
1 REST_FRAMEWORK = { 2 #原碼中會到setting中找PAGE_SIZE,若是找不到會報錯 3 "PAGE_SIZE":4, 4 }
方式一中,全部用PageNumberPagination類來分頁的數據都會由於全局中的"PAGE_SIZE":4,每頁只能分四個
自定義一個分頁器,繼承PageNumberPagination,不一樣的數據能夠每頁顯示不一樣的個數
自定義分頁器類並繼承PageNumberPagination
1 from rest_framework.pagination import PageNumberPagination 2 class MyPagenation(PageNumberPagination): 3 page_size = 3 #每頁顯示多少條數據 4 page_query_param = 'page' #get查詢是?後面的查詢條件 5 page_size_query_param = 'size' #?page=2&size=10,第二頁臨時改爲每頁顯示十條 6 max_page_size = 5 #每頁最多顯示的數據數
使用自定義的分頁器類
1 class BookView(APIView): 2 def get(self,request): 3 #獲取queryset 4 book_list=Book.objects.all() 5 #MyPagenation 6 paginater=MyPagenation() 7 #調用paginate_queryset方法 8 paged_books=paginater.paginate_queryset(book_list,request,self) 9 #將分頁後的數據傳入BookModelSerializer 10 bs=BookModelSerializer(paged_books,many=True,context={'request': request}) 11 return Response(bs.data)
1 from rest_framework.pagination import LimitOffsetPagination 2 3 class MyLimitOffsetPagination(LimitOffsetPagination): 4 default_limit = 3 #每頁顯示幾條數據 5 6 class BookView(APIView): 7 def get(self,request): 8 #獲取queryset 9 book_list=Book.objects.all() 10 #實例化MyLimitOffsetPagination 11 paginater=MyLimitOffsetPagination() 12 #調用paginate_queryset方法 13 paged_books=paginater.paginate_queryset(book_list,request,self) 14 #將分頁後的數據傳入BookModelSerializer 15 bs=BookModelSerializer(paged_books,many=True,context={'request': request}) 16 return Response(bs.data)
訪問http://127.0.0.1:8000/book/?limit=3&offset=2,表示臨時顯示三條數據,偏移兩條數據
1 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination 2 #自定義分頁類 3 class MyPagenation(PageNumberPagination): 4 page_size = 1 5 page_query_param = 'p' 6 page_size_query_param = 'size' 7 max_page_size = 5 8 9 class Aut horViewSet(viewsets.ModelViewSet): 10 queryset = Author.objects.all() 11 serializer_class = AuthorModelSerializer 12 *****爲自定義的ModelViewSet類添加pagination_class字段,綁定分頁器類 13 pagination_class = MyPagenation