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