權(quán)限組件的源碼執(zhí)行過程和之前的認(rèn)證組件是相同的,如下:
成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供楚雄州網(wǎng)站建設(shè)、楚雄州做網(wǎng)站、楚雄州網(wǎng)站設(shè)計、楚雄州網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、楚雄州企業(yè)網(wǎng)站模板建站服務(wù),10余年楚雄州做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
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)
)
思考:如果要做權(quán)限認(rèn)證,我們首先要知道當(dāng)前登錄的用戶是誰,那么我們?nèi)绾沃滥兀?br/>首先rest_framework中的三個組件是按順序執(zhí)行的:
#認(rèn)證組件 self.perform_authentication(request) #權(quán)限組件 self.check_permissions(request) #頻率組件 self.check_throttles(request)
在第一個執(zhí)行的認(rèn)證組件源碼中有這樣一段代碼
self.user, self.auth = user_auth_tuple
這個user_auth_tuple恰巧就是我們自定義認(rèn)證視圖時返回的那個元祖
class TokenAuth(BaseAuthentication): def authenticate(self, request): ...... return token_obj.user, token_obj.token #需要返回一個元組
因此此時的self.user=token_obj.user,self.auth=token_obj.token
在app01.service.permissions.py中:
from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
message = "SVIP才能訪問" #沒通過驗(yàn)證則返回錯誤
def has_permission(self, request, view): #固定寫法
if request.user.user_type == 3:
return True
return False
在views.py:
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中:
from rest_framework.throttling import BaseThrottle
class VisitThrottle(BaseThrottle):
def allow_request(self,request,view):
if 1:
return True
return False
在views.py中:
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#_label3
解析器是將接收到的數(shù)據(jù)轉(zhuǎn)換為我們所需要的數(shù)據(jù)類型,是反序列化的過程,例如將前端傳過來的JSON解析為字典,rest_framework可以直接從request.data中取出反序列化后的JSON數(shù)據(jù),依賴的就是解析器
from rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
parser_classes = [FormParser,JSONParser] #只寫了兩種解析器,默認(rèn)有三種
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',]
}
如果我們自己不設(shè)置parser_classes那么就會去父類中找
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
而父類中的默認(rèn)設(shè)置已經(jīng)包含了常用的三種解析,包括解析JSON數(shù)據(jù)和urlencoded數(shù)據(jù)等,因此這里不太需要修改
'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ),
思考:在實(shí)際開發(fā)過程中,如果我們需要解析一個特殊的數(shù)據(jù)類型,那么可以自己寫一個解析器(類),然后加到parser_classes = []中,這樣就可以在request.data中直接取出這種特殊數(shù)據(jù)類型反序列化后的結(jié)果了
進(jìn)一步封裝url
我們知道下面兩條url都針對一個視圖類,但每個表這寫兩條url的話就會造成代碼重復(fù),因?yàn)椴煌淼拿織lurl只有視圖類的名字和反向解析的名字有區(qū)別而已,這里可以進(jìn)一步封裝
url(r'^authors/$', views.AuthorView.as_view({"get": "list", "post": "create"}), name="author"),
url(r'^authors/(?P\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() #實(shí)例化一個對象
router.register(r'authors', views.AuthorView) #注冊,前面寫表名,后面寫視圖類的名字
urlpatterns = [
url(r'^admin/', admin.site.urls),
url('', include(router.urls)),
]
再訪問就會自動生成四條url
^authors/$ [name='author-list']
^authors\.(?P[a-z0-9]+)/?$ [name='author-list']
^authors/(?P[^/.]+)/$ [name='author-detail']
^authors/(?P[^/.]+)\.(?P[a-z0-9]+)/?$ [name='author-detail']
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
class PNPagination(PageNumberPagination):
page_size = 2 #默認(rèn)每頁顯示幾條
page_query_param = 'page' #url上get請求時的關(guān)鍵字,表示第幾頁 ?page=2
page_size_query_param = 'size' #url關(guān)鍵字,臨時設(shè)置每頁顯示幾條,與默認(rèn)區(qū)分 ?size=2
max_page_size = 3 #用于限制page_size_query_param的最大值,即每頁顯示條數(shù)最多不能超過這個限制
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 #默認(rèn)顯示幾條數(shù)據(jù)
limit_query_param = 'limit' #url關(guān)鍵字,臨時設(shè)置每頁顯示幾條數(shù)據(jù)
offset_query_param = 'offset' #url關(guān)鍵字,偏移,默認(rèn)從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, #數(shù)據(jù)總數(shù)
"next": "http://127.0.0.1:8000/authors/?page=2", #下一頁的url
"previous": null,
......
}
每頁顯示一條數(shù)據(jù)的同時,從第一條數(shù)據(jù)開始向右偏移兩條數(shù)據(jù),顯示結(jié)果是第三條數(shù)據(jù)
http://127.0.0.1:8000/books/?limit=1&offset=2
每頁顯示兩條數(shù)據(jù)的同時,從第一條數(shù)據(jù)開始向右偏移兩條數(shù)據(jù),顯示結(jié)果是第三第四條數(shù)據(jù)
http://127.0.0.1:8000/books/?limit=2&offset=2