zoukankan      html  css  js  c++  java
  • Django----Rest Framework框架

    Django Rest Framework框架(10)

    - RESTful规范

    1.API与用户的通信协议,总是使用HTTPs协议。

    2.域名
    https:
    //api.example.com 尽量将API部署在专用域名(会存在跨域问题) https://example.org/api/ API很简单

    3.版本
    URL,如:https:
    //api.example.com/v1/ 请求头 跨域时,引发发送多次请求


    4.路径,视网络上任何东西都是资源,均使用名词表示(可复数)
    https:
    //api.example.com/v1/zoos https://api.example.com/v1/animals https://api.example.com/v1/employees
    5.method
    GET :从服务器取出资源(一项或多项) POST :在服务器新建一个资源 PUT :在服务器更新资源(客户端提供改变后的完整资源) PATCH :在服务器更新资源(客户端提供改变的属性)
    DELETE :从服务器删除资源

    6.过滤,通过在url上传参的形式传递搜索条件
    https:
    //api.example.com/v1/zoos?limit=10:指定返回记录的数量 https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置 https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数 https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序 https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件

    7.状态码
    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    8.错误处理,应返回错误信息,error当做key。

    { error:
    "Invalid API key" }
    9.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。

    GET
    /collection:返回资源对象的列表(数组) GET /collection/resource:返回单个资源对象 POST /collection:返回新生成的资源对象 PUT /collection/resource:返回完整的资源对象 PATCH /collection/resource:返回完整的资源对象 DELETE /collection/resource:返回一个空文档

    10.Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
    {"link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" }}

    url控制器 

    - 解析器

    全局使用解析器

    setting里

    复制代码
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'
            'rest_framework.parsers.FormParser'
            'rest_framework.parsers.MultiPartParser'
        ]
    
    }
    复制代码

    路由:

    urlpatterns = [
        url(r'test/', TestView.as_view()),
    ]

    视图函数:

    复制代码
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class TestView(APIView):
        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请求,响应内容')
    复制代码

    还有局部使用

    仅处理请求头content-type为application/json的请求体

    url.py

    from django.conf.urls import url, include
    from web.views.s5_parser import TestView
    
    urlpatterns = [
        url(r'test/', TestView.as_view(), name='test'),
    ]

    views.py

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import JSONParser
    
    
    class TestView(APIView):
        parser_classes = [JSONParser, ]
    
        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请求,响应内容')

    仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'test/', TestView.as_view(), name='test'),
    ]
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import FormParser
    
    
    class TestView(APIView):
        parser_classes = [FormParser, ]
    
        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请求,响应内容')

    c. 仅处理请求头content-type为multipart/form-data的请求体

    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'test/', TestView.as_view(), name='test'),
    ]
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import MultiPartParser
    
    
    class TestView(APIView):
        parser_classes = [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请求,响应内容')
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="file" name="img">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>

    d. 仅上传文件

    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
    ]
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import FileUploadParser
    
    
    class TestView(APIView):
        parser_classes = [FileUploadParser, ]
    
        def post(self, request, filename, *args, **kwargs):
            print(filename)
            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请求,响应内容')
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="file" name="img">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>

    e. 同时多个Parser

    当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser

    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'test/', TestView.as_view(), name='test'),
    ]
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    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请求,响应内容')

    参考:https://www.cnblogs.com/liuqingzheng/articles/9766387.html

    局部配置

    视图里:

    from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    
    class Course(APIView):
        renderer_classes = [JSONRenderer,]
        def get(self,request,*args,**kwargs):
            return Response('ok')

    全局配置

    settings.py

    REST_FRAMEWORK={
        'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer',],
    }

     

    - 认证组件

     不存数据库的token验证

    def get_token(id,salt='123'):
        import hashlib
        md=hashlib.md5()
        md.update(bytes(str(id),encoding='utf-8'))
        md.update(bytes(salt,encoding='utf-8'))
    
        return md.hexdigest()+'|'+str(id)
    
    def check_token(token,salt='123'):
        ll=token.split('|')
        import hashlib
        md=hashlib.md5()
        md.update(bytes(ll[-1],encoding='utf-8'))
        md.update(bytes(salt,encoding='utf-8'))
        if ll[0]==md.hexdigest():
            return True
        else:
            return False
    
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            success=check_token(token)
            if success:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    class Login(APIView):
        def post(self,reuquest):
            back_msg={'status':1001,'msg':None}
            try:
                name=reuquest.data.get('name')
                pwd=reuquest.data.get('pwd')
                user=models.User.objects.filter(username=name,password=pwd).first()
                if user:
                    token=get_token(user.pk)
                    # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                    back_msg['status']='1000'
                    back_msg['msg']='登录成功'
                    back_msg['token']=token
                else:
                    back_msg['msg'] = '用户名或密码错误'
            except Exception as e:
                back_msg['msg']=str(e)
            return Response(back_msg)
    from rest_framework.authentication import BaseAuthentication
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if token_obj:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
    View Code

    创建认证类

    from rest_framework.authentication import BaseAuthentication
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if token_obj:
                return token_obj.user,token_obj
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass

    views.py

    def get_random(name):
        import hashlib
        import time
        md=hashlib.md5()
        md.update(bytes(str(time.time()),encoding='utf-8'))
        md.update(bytes(name,encoding='utf-8'))
        return md.hexdigest()
    class Login(APIView):
        def post(self,reuquest):
            back_msg={'status':1001,'msg':None}
            try:
                name=reuquest.data.get('name')
                pwd=reuquest.data.get('pwd')
                user=models.User.objects.filter(username=name,password=pwd).first()
                if user:
                    token=get_random(name)
                    models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                    back_msg['status']='1000'
                    back_msg['msg']='登录成功'
                    back_msg['token']=token
                else:
                    back_msg['msg'] = '用户名或密码错误'
            except Exception as e:
                back_msg['msg']=str(e)
            return Response(back_msg)
    
    
    
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')

    局部使用,只需要在视图类里加入:

    authentication_classes = [TokenAuth, ]

    全局

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
    }

    - 权限组件

    from rest_framework.permissions import BasePermission
    class UserPermission(BasePermission):
        message = '不是超级用户,查看不了'
        def has_permission(self, request, view):
            # user_type = request.user.get_user_type_display()
            # if user_type == '超级用户':
            user_type = request.user.user_type
            print(user_type)
            if user_type == 1:
                return True
            else:
                return False
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
        permission_classes = [UserPermission,]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')

    局部使用只需要在视图类里加入:

    permission_classes = [UserPermission,]

    全局

     

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
    }

     

     

    - 频率组件

    自定义的逻辑

    #(1)取出访问者ip
    # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
    # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
    # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
    # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
    class MyThrottles():
        VISIT_RECORD = {}
        def __init__(self):
            self.history=None
        def allow_request(self,request, view):
            #(1)取出访问者ip
            # print(request.META)
            ip=request.META.get('REMOTE_ADDR')
            import time
            ctime=time.time()
            # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
            if ip not in self.VISIT_RECORD:
                self.VISIT_RECORD[ip]=[ctime,]
                return True
            self.history=self.VISIT_RECORD.get(ip)
            # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
            while self.history and ctime-self.history[-1]>60:
                self.history.pop()
            # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
            # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
            if len(self.history)<3:
                self.history.insert(0,ctime)
                return True
            else:
                return False
        def wait(self):
            import time
            ctime=time.time()
            return 60-(ctime-self.history[-1])
    代码

    内置:

    写一个类,继承自SimpleRateThrottle,(根据ip限制)问:要根据用户现在怎么写

    from rest_framework.throttling import SimpleRateThrottle
    class VisitThrottle(SimpleRateThrottle):
        scope = 'luffy'
        def get_cache_key(self, request, view):
            return self.get_ident(request)

    在setting里配置:(一分钟访问三次)

    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_RATES':{
            'luffy':'3/m'
        }
    }

    在视图类里使用

    throttle_classes = [MyThrottles,]

    中文提示错误:

    class Course(APIView):
        authentication_classes = [TokenAuth, ]
        permission_classes = [UserPermission, ]
        throttle_classes = [MyThrottles,]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
        def throttled(self, request, wait):
            from rest_framework.exceptions import Throttled
            class MyThrottled(Throttled):
                default_detail = '傻逼啊'
                extra_detail_singular = '还有 {wait} second.'
                extra_detail_plural = '出了 {wait} seconds.'
            raise MyThrottled(wait)
    View Code

    - 视图组件 *****

     1 视图类都继承过哪些类
     2 
     3 class View(object):
     4 
     5 
     6 class APIView(View):
     7 
     8 
     9 class GenericAPIView(views.APIView):
    10 
    11 
    12 class GenericViewSet(ViewSetMixin, generics.GenericAPIView)
    13 
    14 
    15 class ModelViewSet(mixins.CreateModelMixin,
    16 
    17 mixins.RetrieveModelMixin,
    18 
    19 mixins.UpdateModelMixin,
    20 
    21 mixins.DestroyModelMixin,
    22 
    23 mixins.ListModelMixin,
    24 
    25 GenericViewSet):
    视图类都继承过哪些类

     

    - 序列化组件 *****

    - 分页器 *****

    CursorPagination(加密分页,只能看上一页和下一页,速度快)

    from rest_framework.pagination import CursorPagination
    # 看源码,是通过sql查询,大于id和小于id
    class  Pager(APIView):
        def get(self,request,*args,**kwargs):
            # 获取所有数据
            ret=models.Book.objects.all()
            # 创建分页对象
            page=CursorPagination()
            page.ordering='nid'
            # 在数据库中获取分页的数据
            page_list=page.paginate_queryset(ret,request,view=self)
            # 对分页进行序列化
            ser=BookSerializer1(instance=page_list,many=True)
            # 可以避免页码被猜到
            return page.get_paginated_response(ser.data)

    偏移分页(在第n个位置,向后查看n条数据)

    复制代码
    # http://127.0.0.1:8000/pager/?offset=4&limit=3
    from rest_framework.pagination import LimitOffsetPagination
    # 也可以自定制,同简单分页
    class  Pager(APIView):
        def get(self,request,*args,**kwargs):
            # 获取所有数据
            ret=models.Book.objects.all()
            # 创建分页对象
            page=LimitOffsetPagination()
            # 在数据库中获取分页的数据
            page_list=page.paginate_queryset(ret,request,view=self)
            # 对分页进行序列化
            ser=BookSerializer1(instance=page_list,many=True)
            # return page.get_paginated_response(ser.data)
            return Response(ser.data)
    复制代码

     

    简单分页(查看第n页,每页显示n条)

     

    复制代码
    from rest_framework.pagination import PageNumberPagination
    # 一 基本使用:url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size无效
    class  Pager(APIView):
        def get(self,request,*args,**kwargs):
            # 获取所有数据
            ret=models.Book.objects.all()
            # 创建分页对象
            page=PageNumberPagination()
            # 在数据库中获取分页的数据
            page_list=page.paginate_queryset(ret,request,view=self)
            # 对分页进行序列化
            ser=BookSerializer1(instance=page_list,many=True)
            return Response(ser.data)
    # 二 自定制 url=http://127.0.0.1:8000/pager/?page=2&size=3
    # size=30,无效,最多5条
    class Mypage(PageNumberPagination):
        page_size = 2
        page_query_param = 'page'
        # 定制传参
        page_size_query_param = 'size'
        # 最大一页的数据
        max_page_size = 5
    class  Pager(APIView):
        def get(self,request,*args,**kwargs):
            # 获取所有数据
            ret=models.Book.objects.all()
            # 创建分页对象
            page=Mypage()
            # 在数据库中获取分页的数据
            page_list=page.paginate_queryset(ret,request,view=self)
            # 对分页进行序列化
            ser=BookSerializer1(instance=page_list,many=True)
            # return Response(ser.data)
            # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
            return page.get_paginated_response(ser.data)

    复制代码

     

    setting里

     

    REST_FRAMEWORK = {
        # 每页显示两条
        'PAGE_SIZE':2
    }

     

     路由:

     

    url(r'^pager/$', views.Pager.as_view()),

     

     Serializers

     

    class BookSerializer1(serializers.ModelSerializer):
        class Meta:
            model=models.Book
            # fields="__all__"
            exclude=('authors',)

     

     

    - 渲染器(响应器)

    
    

    - 版本控制

    内置的版本控制类

    复制代码
    from rest_framework.versioning import QueryParameterVersioning,AcceptHeaderVersioning,NamespaceVersioning,URLPathVersioning
    
    #基于url的get传参方式:QueryParameterVersioning------>如:/users?version=v1
    #基于url的正则方式:URLPathVersioning------>/v1/users/
    #基于 accept 请求头方式:AcceptHeaderVersioning------>Accept: application/json; version=1.0
    #基于主机名方法:HostNameVersioning------>v1.example.com
    #基于django路由系统的namespace:NamespaceVersioning------>example.com/v1/users/
    复制代码

    局部使用

    #在CBV类中加入
    versioning_class = URLPathVersioning

    全局使用

    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.QueryParameterVersioning',
        'DEFAULT_VERSION': 'v1',            # 默认版本(从request对象里取不到,显示的默认值)
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }

    示例

    基于正则的方式:

    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'),
    ]
    复制代码
    from 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请求,响应内容')
    复制代码
            # 基于django内置,反向生成url
            from django.urls import reverse
            url2=reverse(viewname='ttt',kwargs={'version':'v2'})
            print(url2)
    views.py
    
    #局部设置
    from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning
    class Course(APIView):
    
        # versioning_class = QueryParameterVersioning     #get传参
        versioning_class = URLPathVersioning            #url地址 推荐
    
       
        def get(self,request,*args,**kwargs):
            return Response('ok')
    
    
    
    
    settings.py
    
    #全局设置
    REST_FRAMEWORK={
    
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.QueryParameterVersioning',
    
        'ALLOWED_VERSIONS':['v1','v2',], #允许版本
        'VERSION_PARAM':'version', #参数
        'DEFAULT_VERSION':'v1', #默认版本
    
    }
    
    
    
    urls.py
    
        #get传参 http://127.0.0.1:8000/api/course/?version=v1
        url(r'^api/$',include('api.urls')) 
        url(r'^course/$',CourseView.as_view())
    
    api/urls.py
    #url地址 http://127.0.0.1:8000/api/v1/course/ url(r'^api/$',include('api.urls'))
    url(r
    '^(?P<version>[v1|v2]+)/course/$',CourseView.as_view()) #推荐 url(r'^api/(?P<version>w+)/$',include('api.urls')) url(r'^(?P<version>)w+/course/$',CourseView.as_view())

    获取版本
    request.version

    rest_framework 图解

     

     



     

  • 相关阅读:
    基础总结深入:数据类型的分类和判断(数据、内存、变量) 对象 函数 回调函数 IIFE 函数中的this 分号
    BOM 定时器 通过修改元素的类来改变css JSON
    事件 事件的冒泡 事件的委派 事件的绑定 事件的传播
    DOM修改 使用DOM操作CSS
    包装类 Date Math 字符串的相关的方法 正则表达式 DOM DOM查询
    数组 call()、apply()、bind()的使用 this arguments
    autocad 二次开发 最小包围圆算法
    win10 objectarx向导在 vs2015中不起作用的解决办法
    AutoCad 二次开发 jig操作之标注跟随线移动
    AutoCad 二次开发 文字镜像
  • 原文地址:https://www.cnblogs.com/hanbowen/p/9885418.html
Copyright © 2011-2022 走看看