视图三部曲
下面我来来看restframework是如何将冗余的代码一步步的进行封装.
这里主要用到的是多继承
第一步mixin类编写视图
1AuthorModelSerializer: 2 3class AuthorModelSerializer(serializers.ModelSerializer): 4 class Meta: 5 model=models.Author 6 fields='__all__' 7 8from rest_framework import mixins,generics 9class Authors(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView): 10 queryset = models.Author.objects.all() 11 serializer_class = AuthorModelSerializer 12 13 def get(self,request,*args,**kwargs): 14 return self.list(request,*args,**kwargs) 15 16 def post(self,request,*args,**kwargs): 17 return self.create(request,*args,**kwargs) 18 19class AuthorsDetailView(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,generics.GenericAPIView): 20 queryset = models.Author.objects.all() 21 serializer_class = AuthorModelSerializer 22 def get(self,request,*args,**kwargs): 23 return self.retrieve(request,*args,**kwargs) 24 25 def put(self,request,*args,**kwargs): 26 return self.update(request,*args,**kwargs) 27 28 def delete(self,request,*args,**kwargs): 29 return self.delete(request,*args,**kwargs)
第二部使用通用的基于类的视图
1from rest_framework import generics 2 3class Authors(generics.ListCreateAPIView): 4 queryset = models.Author.objects.all() 5 serializer_class = AuthorModelSerializer 6 7 8class AuthorsDetailView(generics.RetrieveUpdateDestroyAPIView): 9 queryset = models.Author.objects.all() 10 serializer_class = AuthorModelSerialize 11 12 13# class ListCreateAPIView(mixins.ListModelMixin, 14# mixins.CreateModelMixin, 15# GenericAPIView): 16# class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, 17# mixins.UpdateModelMixin, 18# mixins.DestroyModelMixin, 19# GenericAPIView):
通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。
到这里是第二部,但是我们还是需要实例化两个类来对应两个url,为什么要实例两个类,因为每个类都有get方法,
如果不写两个类,怎么知道走哪个get方法?
第三部viewsets.ModelViewSet
url部分
1path('authors/', views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'), 2re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorModelView.as_view({'get':'retrieve', 3 'put':'update', 4 'delete':'destroy'}),name='authors_detail'), 5 6##############流程######## 7from rest_framework import viewsets 8class AuthorModelView(viewsets.ModelViewSet): 9ModelViewSet--->GenericViewSet--->ViewSetMixin----在这个类下执行了as_view 10for method, action in actions.items(): 11 #as_view后面的参数倍循环后得到了请求key,相对应的方法values 12 handler = getattr(self, action) # handler -->getattr(self,list) self--->自己写的类AuthorModelView 13 setattr(self, method, handler) #setattr(self,get,self.list) self.get---->执行self.list
view:
1from rest_framework import viewsets 2class AuthorModelView(viewsets.ModelViewSet): 3 queryset = models.Author.objects.all() 4 serializer_class = AuthorModelSerializer
认证组件
局部视图认证:
在app01.authented.py:
1from rest_framework.authentication import BaseAuthentication 2from app01 import models 3from rest_framework.exceptions import AuthenticationFailed 4 5class AuthentiCate(BaseAuthentication): 6 7 def authenticate(self, request): 8 token=request.GET.get('token') 9 token_obj=models.Token.objects.filter(token=token).first() 10 11 if not token_obj: 12 raise AuthenticationFailed('认证失败') 13 return token_obj.user.username,token_obj
在views.py:
1def get_random_str(user): 2 import hashlib,time 3 ctime=str(time.time()) 4 5 md5=hashlib.md5(bytes(user,encoding="utf8")) 6 md5.update(bytes(ctime,encoding="utf8")) 7 8 return md5.hexdigest() 9 10from app01.authented import AuthentiCate 11 12from rest_framework import viewsets 13class AuthorModelView(viewsets.ModelViewSet): 14 ##*******************### 15 authentication_classes = [AuthentiCate] 16 ##*******************### 17 queryset = models.Author.objects.all() 18 serializer_class = AuthorModelSerializer 19 20 21class LoginView(APIView): 22 23 def post(self,request): 24 ret={'status_code':1000,'msg':None} 25 try: 26 username=request.data.get('username') 27 pwd=request.data.get('pwd') 28 29 user=models.User.objects.filter(username=username,pwd=pwd).first() 30 if user: 31 radom_str=get_random_str(user.username) 32 models.Token.objects.update_or_create(user=user,defaults={'token':radom_str}) 33 ret['token']=radom_str 34 else: 35 ret['status_code']=1001 36 ret['msg']='用户名密码错误' 37 except Exception as e: 38 res["code"] = 1002 39 res["msg"] = e 40 41 return Response(data=ret)
全局视图认证组件:
在settings的配置:
1REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.authented.AuthentiCate",] 3}
权限组件
局部权限组件:
在app01.service.permissions.py中:
1from rest_framework.permissions import BasePermission 2class SVIPPermission(BasePermission): 3 message="SVIP才能访问!" 4 def has_permission(self, request, view): 5 if request.user.user_type==3: 6 return True 7 return False
views:
1from app01.service.permissions import * 2 3class BookViewSet(generics.ListCreateAPIView): 4 permission_classes = [SVIPPermission,] 5 queryset = Book.objects.all() 6 serializer_class = BookSerializers
全局视图权限
settings.py配置如下:
1REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], 3 "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",] 4}
如果想添加白名单,在该类下加上permission_classes =[ ]源码找的时候就会先找这里
throttle(访问频率)组件
局部视图throttle:
在app01.service.throttles.py中:
1from rest_framework.throttling import BaseThrottle 2 3VISIT_RECORD={} 4class VisitThrottle(BaseThrottle): 5 6 def __init__(self): 7 self.history=None 8 9 def allow_request(self,request,view): 10 remote_addr = request.META.get('REMOTE_ADDR') 11 print(remote_addr) 12 import time 13 ctime=time.time() 14 15 if remote_addr not in VISIT_RECORD: 16 VISIT_RECORD[remote_addr]=[ctime,] 17 return True 18 19 history=VISIT_RECORD.get(remote_addr) 20 self.history=history 21 22 while history and history[-1]<ctime-60: 23 history.pop() 24 25 if len(history)<3: 26 history.insert(0,ctime) 27 return True 28 else: 29 return False 30 31 def wait(self): 32 import time 33 ctime=time.time() 34 return 60-(ctime-self.history[-1])
在views.py中:
1from app01.service.throttles import * 2 3class BookViewSet(generics.ListCreateAPIView): 4 throttle_classes = [VisitThrottle,] 5 queryset = Book.objects.all() 6 serializer_class = BookSerializers
全局视图的throttle
1REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], 3 "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], 4 "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] 5}
内置的throttle类
1class VisitThrottle(SimpleRateThrottle): 2 3 scope="visit_rate" 4 def get_cache_key(self, request, view): 5 6 return self.get_ident(request)
settings.py设置:
1REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], 3 "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], 4 "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",], 5 "DEFAULT_THROTTLE_RATES":{ 6 "visit_rate":"5/m", 7 } 8}
解析器
1from rest_framework.parsers import JSONParser,FormParser 2class PublishViewSet(generics.ListCreateAPIView): 3######################## 4 parser_classes = [FormParser,JSONParser] 5############################ 6 queryset = Publish.objects.all() 7 serializer_class = PublshSerializers 8 def post(self, request, *args, **kwargs): 9 print("request.data",request.data) 10 return self.create(request, *args, **kwargs)
全局:
1REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], 3 "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], 4 "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",], 5 "DEFAULT_THROTTLE_RATES":{ 6 "visit_rate":"5/m", 7 }, 8 "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',] 9}
URL的编写
1from django.conf.urls import url, include 2from rest_framework import routers 3from tutorial.quickstart import views 4 5router = routers.DefaultRouter() 6router.register(r'authors', views.AuthorsViewSet) 7 8 9urlpatterns = [ 10 url(r'^', include(router.urls)),
只要注册了router.register,就会有相对应的
1path('authors/',views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'), 2re_path(r'^authors/(?P<pk>\d+)/$',views.AuthorModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'}),name='authors_detail'),
并且还相应的增加了其他两条restframework的测试url
分页
分页之自定义:
第一版:
1from rest_framework.pagination import PageNumberPagination 2class Mypagination(PageNumberPagination): 3 page_size = 1 4 page_query_param = 'page' 5 page_size_query_param = "size" 6 max_page_size = 5 7 8class BookView(APIView): 9 # authentication_classes = [TokenAuth,] # [TokenAuth(),] 10 # permission_classes = [] 11 # throttle_classes = [] 12 13 def get(self,request): 14 book_list=Book.objects.all() 15 16 # 分页 17 18 pnp=Mypagination() 19 books_page=pnp.paginate_queryset(book_list,request,self) 20 21 bs=BookModelSerializers(books_page,many=True,context={'request': request}) 22 return Response(bs.data)
分页之最终版:
1from rest_framework.pagination import PageNumberPagination 2class Mypagination(PageNumberPagination): 3 page_size = 1 4 page_query_param = 'page' 5 page_size_query_param = "size" 6 max_page_size = 5 7 8from rest_framework import viewsets 9class AuthorModelView(viewsets.ModelViewSet): 10 queryset = models.Author.objects.all() 11 serializer_class = AuthorModelSerializer 12 pagination_class = Mypagination
偏移分页
from rest_framework.pagination import LimitOffsetPagination
版本的设置
1.设置settings:
1REST_FRAMEWORK={ 2 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',#路由配置版本 3 'DEFAULT_VERSION':'v1', #默认的版本 4 'ALLOWED_VERSIONS':['v1','v2'], #允许的版本 5 'VERSION_PARAM':'version', # 版本参数
2.设置路由:
分发的时候设置:
1urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path(r'^api/(?P<version>\w+)/', include('api.urls')), 4]
3.获取版本:
request.version #获取版本
跨域请求CORS
1CORS: 2解决跨域的时候是加上特殊的响应头 3jsonp跨域只能是get请求, 4cors可以发送post和get请求. 5 6配置中间件 7from django.utils.deprecation import MiddlewareMixin 8class CORSMiddleware(MiddlewareMixin): 9 def process_response(self,request,response): 10 #添加响应头 11 # 允许你的域名来获取我的数据 12 # 允许所有的域名来获取数据 13 response['Access-Control-Allow-Origin']='*' 14 15 # 允许你携带Content-Type请求头 如果要多的用逗号,隔开 16 response['Access-Control-Allow-Headers']='Content-Type' 17 18 # 允许你发送DELETE,和PUT 19 response['Access-Control-Allow-Methods']='DELETE,PUT' 20 21 return response 22#setting里配置 23MIDDLEWARE = [ 24'api.cors.CORSMiddleware', 25]