权限组件的源码执行过程和之前的认证组件是相同的,如下:
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)
在第一个执行的认证组件源码中有这样一段代码
self.user, self.auth = user_auth_tuple
这个user_auth_tuple恰巧就是我们自定义认证视图时返回的那个元祖
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才能访问" #没通过验证则返回错误
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
解析器是将接收到的数据转换为我们所需要的数据类型,是反序列化的过程,例如将前端传过来的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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。