權限組件的源碼執行過程和以前的認證組件是相同的,以下:html
self.check_permissions(request)
def check_permissions(self, request): """ Check if the request should be permitted. Raises an appropriate exception if the request is not permitted. """ for permission in self.get_permissions(): if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) )
思考:若是要作權限認證,咱們首先要知道當前登陸的用戶是誰,那麼咱們如何知道呢?
首先rest_framework中的三個組件是按順序執行的:前端#認證組件 self.perform_authentication(request) #權限組件 self.check_permissions(request) #頻率組件 self.check_throttles(request)在第一個執行的認證組件源碼中有這樣一段代碼django
self.user, self.auth = user_auth_tuple這個user_auth_tuple恰巧就是咱們自定義認證視圖時返回的那個元祖api
class TokenAuth(BaseAuthentication): def authenticate(self, request): ...... return token_obj.user, token_obj.token #須要返回一個元組所以此時的self.user=token_obj.user,self.auth=token_obj.tokenapp
在app01.service.permissions.py中:ide
from rest_framework.permissions import BasePermission class SVIPPermission(BasePermission): message = "SVIP才能訪問" #沒經過驗證則返回錯誤 def has_permission(self, request, view): #固定寫法 if request.user.user_type == 3: return True return False
在views.py:post
class AuthorView(viewsets.ModelViewSet): authentication_classes = [TokenAuth,] permission_classes = [SVIPPermission,] queryset = Author.objects.all() serializer_class = AuthorModelSerializers
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",] }
self.check_throttles(request)
def check_throttles(self, request): """ Check if request should be throttled. Raises an appropriate exception if the request is throttled. """ for throttle in self.get_throttles(): if not throttle.allow_request(request, self): self.throttled(request, throttle.wait())
在app01.service.throttles.py中:url
from rest_framework.throttling import BaseThrottle class VisitThrottle(BaseThrottle): def allow_request(self,request,view): if 1: return True return False
在views.py中:rest
from app01.service.throttles import * class BookViewSet(generics.ListCreateAPIView): throttle_classes = [VisitThrottle,] queryset = Book.objects.all() serializer_class = BookSerializers
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] }
https://www.cnblogs.com/yuanchenqi/articles/8719520.html#_label3code
解析器是將接收到的數據轉換爲咱們所須要的數據類型,是反序列化的過程,例如將前端傳過來的JSON解析爲字典,rest_framework能夠直接從request.data中取出反序列化後的JSON數據,依賴的就是解析器
from rest_framework.parsers import JSONParser,FormParser class PublishViewSet(generics.ListCreateAPIView): parser_classes = [FormParser,JSONParser] #只寫了兩種解析器,默認有三種 queryset = Publish.objects.all() serializer_class = PublshSerializers def post(self, request, *args, **kwargs): print("request.data",request.data) return self.create(request, *args, **kwargs)
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",], "DEFAULT_THROTTLE_RATES":{ "visit_rate":"5/m", }, "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',] }
若是咱們本身不設置parser_classes那麼就會去父類中找
parser_classes = api_settings.DEFAULT_PARSER_CLASSES而父類中的默認設置已經包含了經常使用的三種解析,包括解析JSON數據和urlencoded數據等,所以這裏不太須要修改
'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ),思考:在實際開發過程當中,若是咱們須要解析一個特殊的數據類型,那麼能夠本身寫一個解析器(類),而後加到parser_classes = []中,這樣就能夠在request.data中直接取出這種特殊數據類型反序列化後的結果了
進一步封裝url
咱們知道下面兩條url都針對一個視圖類,但每一個表這寫兩條url的話就會形成代碼重複,由於不一樣表的每條url只有視圖類的名字和反向解析的名字有區別而已,這裏能夠進一步封裝
url(r'^authors/$', views.AuthorView.as_view({"get": "list", "post": "create"}), name="author"), url(r'^authors/(?P<pk>\d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailauthor"),
class AuthorView(viewsets.ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorModelSerializers
from rest_framework import routers from django.conf.urls import include from app01 import views router = routers.DefaultRouter() #實例化一個對象 router.register(r'authors', views.AuthorView) #註冊,前面寫表名,後面寫視圖類的名字 urlpatterns = [ url(r'^admin/', admin.site.urls), url('', include(router.urls)), ]
再訪問就會自動生成四條url
^authors/$ [name='author-list'] ^authors\.(?P<format>[a-z0-9]+)/?$ [name='author-list'] ^authors/(?P<pk>[^/.]+)/$ [name='author-detail'] ^authors/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='author-detail']
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
class PNPagination(PageNumberPagination): page_size = 2 #默認每頁顯示幾條 page_query_param = 'page' #url上get請求時的關鍵字,表示第幾頁 ?page=2 page_size_query_param = 'size' #url關鍵字,臨時設置每頁顯示幾條,與默認區分 ?size=2 max_page_size = 3 #用於限制page_size_query_param的最大值,即每頁顯示條數最多不能超過這個限制
class MyLimitOffsetPagination(LimitOffsetPagination): default_limit = 3 #默認顯示幾條數據 limit_query_param = 'limit' #url關鍵字,臨時設置每頁顯示幾條數據 offset_query_param = 'offset' #url關鍵字,偏移,默認從0開始,與limit能夠配合
class BookView(APIView): def get(self, request): book_list = Book.objects.all() # 分頁 pnp = MyLimitOffsetPagination() pager_books = pnp.paginate_queryset(book_list, request, self) ret = BookModelSerializers(pager_books, many=True, context={'request': request}) # 此處的Response來自rest_framework return Response(ret.data)
class AuthorView(viewsets.ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorModelSerializers pagination_class = MyLimitOffsetPagination #定義分頁器類
返回值 { "count": 4, #數據總數 "next": "http://127.0.0.1:8000/authors/?page=2", #下一頁的url "previous": null, ...... }
每頁顯示一條數據的同時,從第一條數據開始向右偏移兩條數據,顯示結果是第三條數據
http://127.0.0.1:8000/books/?limit=1&offset=2
每頁顯示兩條數據的同時,從第一條數據開始向右偏移兩條數據,顯示結果是第三第四條數據
http://127.0.0.1:8000/books/?limit=2&offset=2