Django Rest Framework框架组件的执行流程
1 2 3 | rest framework组件为我们提供了下面的这些功能: 按照HTTP请求的生命周期去记; 先是进入路由,在视图,进入dispatch()里面,然 后提供的是版本,权限,认证,频率,然后从 解析器()里面取数据,再序列化,分页,渲染器。 |
1.认证和授权
a. 用户url传入的token认证(作为url的参数传入)
1 2 3 4 5 6 | from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ url(r '^test/' , TestView.as_view()), ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions from .models import * class TokenAuth(BaseAuthentication): def authenticate( self , request): token = request.GET.get( "token" ) # request.query_params ---> request.GET token_obj = Token.objects. filter (token = token).first() if not token_obj: raise exceptions.AuthenticationFailed( "验证失败123!" ) else : return token_obj.user, token_obj.token # 返回一个元组 request.user, request.auth # def authenticate_header(self, request): # pass # 只是我们继承了BaseAuthentication的认证组件 就不用写了。 class TestView(APIView): authentication_classes = [TokenAuth, ] permission_classes = [] def get( self , request, * args, * * kwargs): print (request.user) print (request.auth) return Response( 'GET请求,响应内容' ) def post( self , request, * args, * * kwargs): return Response( 'POST请求,响应内容' ) views.py |
认证和权限
1 2 3 4 5 6 | from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r '^test/' , TestView.as_view()), ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import BasePermission from rest_framework.request import Request from rest_framework import exceptions from .models import * class TokenAuth(BaseAuthentication): def authenticate( self , request): token = request.GET.get( "token" ) # request.query_params ---> request.GET token_obj = Token.objects. filter (token = token).first() if not token_obj: raise exceptions.AuthenticationFailed( "验证失败123!" ) else : return token_obj.user.pk, token_obj.token # 返回一个元组 request.user, request.auth # def authenticate_header(self, request): # pass # 只是我们继承了BaseAuthentication的认证组件 就不用写了。 class SVIPPermisson(BasePermission): message = "没有SVIP权限" # 错误信息 def has_permission( self , request, view): if request.user = = 1 : # request.user.pk 是从认证组件里面取的 return True else : return False #没有权限 class TestView(APIView): # 认证的动作是由request.user触发 authentication_classes = [TestAuthentication, ] # 权限 # 循环执行所有的权限 permission_classes = [TestPermission, ] def get( self , request, * args, * * kwargs): # self.dispatch print (request.user) print (request.auth) return Response( 'GET请求,响应内容' ) def post( self , request, * args, * * kwargs): return Response( 'POST请求,响应内容' ) views.py |
全局使用权限和认证,就需要在settings里面去配置全局信息。
1 2 3 4 5 6 7 8 9 10 | REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES" : [ "web.utils.TestAuthentication" , ], "DEFAULT_PERMISSION_CLASSES" : [ "web.utils.TestPermission" , ], } settings.py |
2.用户访问次数/频率限制
a. 基于用户IP限制访问频率
这种方法是无法控制的,因为用户可以换代理IP,所以没有完全的限制。
1 2 3 4 5 6 7 8 | from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r '^test/' , TestView.as_view()), ] urls.py |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #!/usr/bin/env python # -*- coding:utf-8 -*- import time from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import exceptions from rest_framework.throttling import BaseThrottle from rest_framework.settings import api_settings # 保存访问记录 RECORD = { '用户IP' : [ 12312139 , 12312135 , 12312133 , ] } class TestThrottle(BaseThrottle): ctime = time.time def get_ident( self , request): """ 根据用户IP和代理IP,当做请求者的唯一IP Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR if present and number of proxies is > 0. If not use all of HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. """ xff = request.META.get( 'HTTP_X_FORWARDED_FOR' ) remote_addr = request.META.get( 'REMOTE_ADDR' ) num_proxies = api_settings.NUM_PROXIES if num_proxies is not None : if num_proxies = = 0 or xff is None : return remote_addr addrs = xff.split( ',' ) client_addr = addrs[ - min (num_proxies, len (addrs))] return client_addr.strip() return ''.join(xff.split()) if xff else remote_addr def allow_request( self , request, view): """ 是否仍然在允许范围内 Return `True` if the request should be allowed, `False` otherwise. :param request: :param view: :return: True,表示可以通过;False表示已超过限制,不允许访问 """ # 获取用户唯一标识(如:IP) # 允许一分钟访问10次 num_request = 10 time_request = 60 now = self .ctime() ident = self .get_ident(request) self .ident = ident if ident not in RECORD: RECORD[ident] = [now, ] return True history = RECORD[ident] while history and history[ - 1 ] < = now - time_request: #剔除 超时或者是不符合的时间戳。 history.pop() if len (history) < num_request: #判断当前IP的访问的次数(通过时间戳的数量) history.insert( 0 , now) #把当前的访问的时间戳放在第一个。 return True def wait( self ): """ 多少秒后可以允许继续访问 Optionally, return a recommended number of seconds to wait before the next request. """ #last_time = RECORD[self.ident][0] #last_time 就是代表最长时间后才可以继续访问。 min_time = RECORD[ self .ident][ - 1 ] #列表中最后一个是最小的时间,当最小的时间失效后就可以访问了。 now = self .ctime() return int ( 60 + min_time - now) #还有多少秒可以继续访问,就代表着列表中最后一个时间失效剔除后,列表中的个数就少于次数了,这样不就可以访问了吗?也是可以访问的最小时间。 class TestView(APIView): throttle_classes = [TestThrottle, ] def get( self , request, * args, * * kwargs): # self.dispatch print (request.user) print (request.auth) return Response( 'GET请求,响应内容' ) def post( self , request, * args, * * kwargs): return Response( 'POST请求,响应内容' ) def put( self , request, * args, * * kwargs): return Response( 'PUT请求,响应内容' ) def throttled( self , request, wait): """ 访问次数被限制时,定制错误信息 """ class Throttled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = '请 {wait} 秒之后再重试.' extra_detail_plural = '请 {wait} 秒之后再重试.' raise Throttled(wait) views.py |
b. 基于用户IP显示访问频率(利于Django缓存)常用的
1 2 3 4 5 | REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES' : { 'test_scope' : '10/m' , }, } |
在源码中
1 2 3 4 | num, period = rate.split( '/' ) num_requests = int (num) duration = { 's' : 1 , 'm' : 60 , 'h' : 3600 , 'd' : 86400 }[period[ 0 ]] return (num_requests, duration) |
即通过/分割,前面是允许访问的次数,后面是时间。
即在60s内可以访问的次数为10次
1 2 3 4 5 6 | from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r '^test/' , TestView.as_view()), ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import exceptions from rest_framework.throttling import SimpleRateThrottle class TestThrottle(SimpleRateThrottle): # 配置文件定义的显示频率的Key scope = "test_scope" def get_cache_key( self , request, view): """ Should return a unique cache-key which can be used for throttling. Must be overridden. May return `None` if the request should not be throttled. """ if not request.user: ident = self .get_ident(request) else : ident = request.user return self .cache_format % { 'scope' : self .scope, 'ident' : ident } class TestView(APIView): throttle_classes = [TestThrottle, ] def get( self , request, * args, * * kwargs): # self.dispatch print (request.user) print (request.auth) return Response( 'GET请求,响应内容' ) def post( self , request, * args, * * kwargs): return Response( 'POST请求,响应内容' ) def put( self , request, * args, * * kwargs): return Response( 'PUT请求,响应内容' ) def throttled( self , request, wait): """ 访问次数被限制时,定制错误信息 """ class Throttled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = '请 {wait} 秒之后再重试.' extra_detail_plural = '请 {wait} 秒之后再重试.' raise Throttled(wait) views.py |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 如何实现的访问频率控制? 访问频率控制的原理: 用户进来时候,把它的访问时间记录全部放进来,然后每次再访问进来时候,把超时或者是不符合的时间戳给剔除。 然后根据它时间记录的个数来做判断。 匿名用户:无法控制,因为用户可以换代理IP,所以没发做。 { 192.168 . 1.1 :[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], 192.168 . 1.2 :[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], 192.168 . 1.3 :[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], 192.168 . 1.4 :[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], 192.168 . 1.5 :[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], 192.168 . 1.6 :[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], 先剔除时间 } 真要做匿名用户的访问频率的话,可以给匿名用户给随机的字符串,然后给每次访问的时候都带着,用它来记录时间,但是这样也不行,因为浏览器如果不带的话,每次都是第一次访问。凭我现在的能力,还没有办法能解决,想问您有什么解决的好办法呢 登录用户:如果有很多账号,也无法限制 { alex:[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], eric:[ 1521223123.232 , 1521223122.232 , 1521223121.232 ], } 参考源码: from rest_framework.throttling import SimpleRateThrottle |
SimpleRateThrottle请求频率源码分析
https://blog.csdn.net/u013210620/article/details/79898512
3.版本
a. 基于url的get传参方式(QueryParameterVersioning)
如:/users?version=v1
1 2 3 4 5 | REST_FRAMEWORK = { 'DEFAULT_VERSION' : 'v1' , # 默认版本 'ALLOWED_VERSIONS' : [ 'v1' , 'v2' ], # 允许的版本 'VERSION_PARAM' : 'version' # URL中获取值的key } |
1 2 3 4 5 6 | from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r '^test/' , TestView.as_view(),name = 'test' ), ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import QueryParameterVersioning class TestView(APIView): versioning_class = QueryParameterVersioning def get( self , request, * args, * * kwargs): # 获取版本 print (request.version) # 获取版本管理的类 print (request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse( 'test' , request = request) print (reverse_url) return Response( 'GET请求,响应内容' ) def post( self , request, * args, * * kwargs): return Response( 'POST请求,响应内容' ) def put( self , request, * args, * * kwargs): return Response( 'PUT请求,响应内容' ) |
1 2 3 | from rest_framework.versioning import URLPathVersioning,QueryParameterVersioning # URLPathVersioning 是把版本放在url上;最常用的 # QueryParameterVersioning 是把版本当做get的参数 ?version |
基于url的正则方式(URLPathVersioning)
如:/v1/users/
1 2 3 4 5 | REST_FRAMEWORK = { 'DEFAULT_VERSION' : 'v1' , # 默认版本 'ALLOWED_VERSIONS' : [ 'v1' , 'v2' ], # 允许的版本 'VERSION_PARAM' : 'version' # URL中获取值的key } |
1 2 3 4 5 6 | from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r '^(?P<version>[v1|v2]+)/test/' , TestView.as_view(), name = 'test' ), ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | rom rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import URLPathVersioning class TestView(APIView): versioning_class = URLPathVersioning def get( self , request, * args, * * kwargs): # 获取版本 print (request.version) # 获取版本管理的类 print (request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse( 'test' , request = request) print (reverse_url) return Response( 'GET请求,响应内容' ) def post( self , request, * args, * * kwargs): return Response( 'POST请求,响应内容' ) def put( self , request, * args, * * kwargs): return Response( 'PUT请求,响应内容' ) |
全局使用
1 2 3 4 5 6 | REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS' : "rest_framework.versioning.URLPathVersioning" , 'DEFAULT_VERSION' : 'v1' , 'ALLOWED_VERSIONS' : [ 'v1' , 'v2' ], 'VERSION_PARAM' : 'version' } |
更多的方式参考https://www.cnblogs.com/wupeiqi/articles/7805382.html
4. 解析器(parser)
1 2 3 4 5 6 7 8 9 10 11 | #解析器 from rest_framework.parsers import JSONParser from rest_framework.parsers import FormParser from rest_framework.parsers import MultiPartParser from rest_framework.parsers import FileUploadParser # parser_classes = [JSONParser,FormParser,MultiPartParser] #解析器,即按照content-type的不同来处理数据 #仅处理请求头content-type为application/json的请求体为JSONParser #仅处理请求头content-type为application/x-www-form-urlencoded 的请求体为FormParser #仅处理请求头content-type为multipart/form-data的请求体为MultiPartParser #form表单上传文件 |
同时多个Parser,单个使用的使用就写需要用的那个
1 2 3 4 5 6 | from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r 'test/' , TestView.as_view(), name = 'test' ), ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import JSONParser, FormParser, MultiPartParser class TestView(APIView): parser_classes = [JSONParser, FormParser, MultiPartParser, ] def post( self , request, * args, * * kwargs): print (request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理 print (request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 print (request.POST) print (request.FILES) return Response( 'POST请求,响应内容' ) def put( self , request, * args, * * kwargs): return Response( 'PUT请求,响应内容' ) |
全局使用
1 2 3 4 5 6 7 8 | REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES' :[ 'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser' ] } |
注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取
5. 序列化
序列化用于对用户请求数据进行验证和数据进行序列化
基于Model自动生成字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | from rest_framework import serializers from app01.models import * class CouserSerializers(serializers.ModelSerializer): ''' 课程的序列化 ''' #自定义的字段 #source为表里面的所有字段 level = serializers.CharField(source = 'get_level_display' ) #自动的帮你添加() course_type = serializers.CharField(source = 'get_course_type_display' ) class Meta: model = Course fields = [ "id" , 'name' , "course_img" , "course_type" , "brief" , "level" , "period" ] # depth=2 用深度帮你进行跨表 class CourseDetailViewSerializers(serializers.ModelSerializer): ''' 详细课程的序列化 ''' #一对一的反向查询,fk,choice都是用source,只能取一条或者是一个数据 name = serializers.CharField(source = 'course.name' ) img = serializers.CharField(source = 'course.course_img' ) content = serializers.CharField(source = 'course.brief' ) id = serializers.CharField(source = 'course.id' ) #多对多的,用SerializerMethodField(),可以获取多个 #推荐课程 recommend_courses = serializers.SerializerMethodField() #老师 teachers = serializers.SerializerMethodField() # 每个时间段的价格 price = serializers.SerializerMethodField() # 课程大纲 course_detail = serializers.SerializerMethodField() #课程章节 coursechapter = serializers.SerializerMethodField() # # #课时目录 # coursesection = serializers.SerializerMethodField() # 推荐课程 def get_recommend_courses( self ,obj): #obj--> CourseDetail.obj # obj.recommendcourse.all() return [{ "id" :item. id , "title" :item.name} for item in obj.recommend_courses. all ()] def get_teachers( self ,obj): #obj--> CourseDetail.obj # obj.recommendcourse.all() return [{ "id" :item. id , "name" :item.name, "title" :item.title} for item in obj.teachers. all ()] # 每个时间段的价格 def get_price( self ,obj): return [{ "valid_period" :item.get_valid_period_display(), "price" :item.price} for item in obj.course.price_policy. all ()] def get_course_detail( self ,obj): return [{ "title" :item.title, "content" :item.content} for item in obj.courseoutline_set. all ()] def get_coursechapter( self ,obj): return [{ "chapter" :item.chapter, "title" :item.name, "summarys" :item.summary} for item in obj.course.coursechapters. all ()] # def get_coursesection(self,obj): # return [{"chapter":item.chapter,"name":item.name,"summary":item.summary}for item in obj.course.coursechapters.coursesections.all()] class Meta: model = CourseDetail fields = [ "id" , "name" , "img" , "hours" , "teachers" , "content" , 'why_study' , "what_to_study_brief" , "career_improvement" , "prerequisite" , "recommend_courses" , "price" , 'course_detail' , 'coursechapter' ,] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class TestView(APIView): def get( self , request, * args, * * kwargs): # 序列化,将数据库查询字段序列化为字典 data_list = models.UserInfo.objects. all () ser = CourseDetailViewSerializers(instance = data_list, many = True ) # 或 # obj = models.UserInfo.objects.all().first() # ser = CourseDetailViewSerializers(instance=obj, many=False) return Response(ser.data) def post( self , request, * args, * * kwargs): # 验证,对请求发来的数据进行验证 print (request.data) ser = CourseDetailViewSerializers(data = request.data) if ser.is_valid(): print (ser.validated_data)<br> ser.save() #直接保存到数据库,在这里会调用GoodSerializer的create方法。<br> else : print (ser.errors) return Response( 'POST请求,响应内容' ) |
6. 分页
a根据页码进行分页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | from rest_framework.views import APIView from rest_framework import serializers from .. import models from rest_framework.pagination import PageNumberPagination class StandardResultsSetPagination(PageNumberPagination): # 默认每页显示的数据条数 page_size = 1 # 获取URL参数中设置的每页显示数据条数 page_size_query_param = 'page_size' # 获取URL参数中传入的页码key page_query_param = 'page' # 最大支持的每页显示的数据条数 max_page_size = 1 class UserSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class UserViewSet(APIView): def get( self , request, * args, * * kwargs): user_list = models.UserInfo.objects. all ().order_by( '-id' ) # 实例化分页对象,获取数据库中的分页数据 paginator = StandardResultsSetPagination() page_user_list = paginator.paginate_queryset(user_list, self .request, view = self ) # 序列化对象 serializer = UserSerializer(page_user_list, many = True ) # 生成分页和数据 response = paginator.get_paginated_response(serializer.data) return response |
b位置和个数进行分页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from rest_framework.views import APIView from rest_framework import serializers from .. import models from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class StandardResultsSetPagination(LimitOffsetPagination): # 默认每页显示的数据条数 default_limit = 10 # URL中传入的显示数据条数的参数 limit_query_param = 'limit' # URL中传入的数据位置的参数 offset_query_param = 'offset' # 最大每页显得条数 max_limit = None class UserSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class UserViewSet(APIView): def get( self , request, * args, * * kwargs): user_list = models.UserInfo.objects. all ().order_by( '-id' ) # 实例化分页对象,获取数据库中的分页数据 paginator = StandardResultsSetPagination() page_user_list = paginator.paginate_queryset(user_list, self .request, view = self ) # 序列化对象 serializer = UserSerializer(page_user_list, many = True ) # 生成分页和数据 response = paginator.get_paginated_response(serializer.data) return response views.py |
7. 路由系统
a. 自定义路由
1 2 3 4 5 6 7 8 9 | from django.conf.urls import url, include from web.views import s11_render urlpatterns = [ url(r '^test/$' , s11_render.TestView.as_view()), url(r '^test\.(?P<format>[a-z0-9]+)$' , s11_render.TestView.as_view()), url(r '^test/(?P<pk>[^/.]+)/$' , s11_render.TestView.as_view()), url(r '^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$' , s11_render.TestView.as_view()) ] |
b. 半自动路由
1 2 3 4 5 6 | from django.conf.urls import url,include from django.contrib import admin from app01 import views url(r '^api/(?P<version>\w+)/bookviewset/$' , views.BookViewSet.as_view({ "get" : "list" , "post" : "create" }),name = 'bookviewset' ), url(r '^api/bookviewset/$' , views.BookViewSet.as_view({ "get" : "list" , "post" : "create" }),name = 'bookviewset' ), |
1 | # url(r'^bookviewset/(?P<pk>\d+)$', views.BookViewSet.as_view({"get":"retrieve","post":"update"}), name='bookviewsetdetail'), |
c. 全自动路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from django.conf.urls import url,include from rest_framework import routers from app01 import views router = routers.DefaultRouter() router.register( "bookviewset" ,views.BookViewSet) url(r'',include(router.urls)), #自动的帮你生成4个url #^bookviewset/$ [name='book-list'] #^bookviewset\.(?P<format>[a-z0-9]+)/?$ [name='book-list'] .json\?format=json #^bookviewset/(?P<pk>[^/.]+)/$ [name='book-detail'] #^bookviewset/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail'] |
8. 视图
根据继承的类的不同有不同的形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class View( object ): class APIView(View): class GenericAPIView(views.APIView): class GenericViewSet(ViewSetMixin, generics.GenericAPIView) # ViewSetMixin 是对as_view里面的参数进行处理 class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): |
ViewSetMixin
1 | url(r '^api/(?P<version>\w+)/bookviewset/$' , views.BookViewSet.as_view({ "get" : "list" , "post" : "create" }),name = 'bookviewset' ) |
没有继承ViewSetMixin 这个类的话get请求就是执行对应的get的方法。
ModelViewSet把上面的增删改查都包含了,减少了我们自己写麻烦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from app01.forms import TokenAuth,SVIPPermisson #解析器 from rest_framework.parsers import JSONParser from rest_framework.parsers import FormParser from rest_framework.parsers import MultiPartParser #版本 from rest_framework.versioning import URLPathVersioning,QueryParameterVersioning class BookViewSet(viewsets.ModelViewSet): authentication_classes = [TokenAuth,] #认证组件 # permission_classes = [SVIPPermisson,] #权限组件 # throttle_classes = [] #频率组件 # parser_classes = [JSONParser,FormParser,MultiPartParser] #解析器,即按照content-type的不同来处理数据 queryset = Book.objects. all () # 取的数据 print (queryset) serializer_class = BookModelSerializers # 序列化器 pagination_class = MyPageNumberPagination #分页器 |
10. 渲染器
根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件。
a. json
访问URL:
- http://127.0.0.1:8000/test/?format=json
- http://127.0.0.1:8000/test.json
- http://127.0.0.1:8000/test/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from rest_framework.renderers import JSONRenderer from .. import models class TestSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class TestView(APIView): renderer_classes = [JSONRenderer, ] def get( self , request, * args, * * kwargs): user_list = models.UserInfo.objects. all () ser = TestSerializer(instance = user_list, many = True ) return Response(ser.data) |
b. 表格
访问URL:
- http://127.0.0.1:8000/test/?format=admin
- http://127.0.0.1:8000/test.admin
- http://127.0.0.1:8000/test/
1 | from rest_framework.renderers import AdminRenderer |
1 | renderer_classes = [AdminRenderer, ] |
c. Form表单
访问URL:
- http://127.0.0.1:8000/test/?format=form
- http://127.0.0.1:8000/test.form
- http://127.0.0.1:8000/test/
1 2 | from rest_framework.renderers import HTMLFormRenderer renderer_classes = [HTMLFormRenderer, ] |
等更多渲染器的形式点击查看
完整全面的内容点击
# URLPathVersioning 是把版本放在url上;最常用的
# QueryParameterVersioning 是把版本当做get的参数 ?version
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· 对象命名为何需要避免'-er'和'-or'后缀
· JDK 24 发布,新特性解读!
· Java24你发任你发,我用Java8
· .NET Core奇技淫巧之WinForm使用Python.NET并打包
· C# 中比较实用的关键字,基础高频面试题!