zoukankan      html  css  js  c++  java
  • Django rest framework

        1. 开发模式
            - 普通开发方式(前后端放在一起写)
            - 前后端分离
        
        2. 后端开发
            为前端提供URL(API/接口的开发)
            注:永远返回HttpResponse

    Django的FBV和CBV

    FBV :function base view

    def users(request):
        user_list = ['alex','oldboy']
        return HttpResponse(json.dumps((user_list)),status=200) #状态码

    CBV:class base view

    路由:
        url(r'^students/', views.StudentsView.as_view()),
    试图:
        #根据请求方式不同自动调用相应的方法
        from django.views import View
    
        class StudentsView(View):
    
         def get(self,request,*args,**kwargs):
             return HttpResponse('GET',status=200)
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST',status=200)
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT',status=200)
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE',status=200)    

    原理:

    CBV,基于反射实现根据请求方式不同,执行不同的方法。
    
    url -> view方法 -> dispatch方法(反射执行其他:GET/POST/DELETE/PUT)

    流程:

    流程:
        class StudentsView(View):
            def dispatch(self, request, *args, **kwargs):
                print('before')
                ret = super(StudentsView,self).dispatch(request, *args, **kwargs)
                print('after')
                return ret
    
            def get(self,request,*args,**kwargs):
                return HttpResponse('GET')
    
            def post(self, request, *args, **kwargs):
                return HttpResponse('POST')
    
            def put(self, request, *args, **kwargs):
                return HttpResponse('PUT')
    
            def delete(self, request, *args, **kwargs):
                return HttpResponse('DELETE')

    继承:多个类共用的功能,为了避免重复编写

    继承(多个类共用的功能,为了避免重复编写):
        from django.views import View
    
    
        class MyBaseView(object):
            def dispatch(self, request, *args, **kwargs):
                print('before')
                ret = super(MyBaseView,self).dispatch(request, *args, **kwargs)
                print('after')
                return ret
    
        class StudentsView(MyBaseView,View):
    
            def get(self,request,*args,**kwargs):
                print('get方法')
                return HttpResponse('GET')
    
            def post(self, request, *args, **kwargs):
                return HttpResponse('POST')
    
            def put(self, request, *args, **kwargs):
                return HttpResponse('PUT')
    
            def delete(self, request, *args, **kwargs):
                return HttpResponse('DELETE')
    
        class TeachersView(MyBaseView,View):
    
            def get(self,request,*args,**kwargs):
                return HttpResponse('GET')
    
            def post(self, request, *args, **kwargs):
                return HttpResponse('POST')
    
            def put(self, request, *args, **kwargs):
                return HttpResponse('PUT')
    
            def delete(self, request, *args, **kwargs):
                return HttpResponse('DELETE')
    

      

    什么是RESTful

    REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
    
    REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
    
    所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
    
    对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
    

      

    restful API设计  规范

    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:指定返回记录的开始位置
    
    7.状态码
    
    8.错误处理,状态码是4xx时,应返回错误信息,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"
        }}
    

      

    csrf装饰器的使用

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    
    # @csrf_protect #需要验证
    # @csrf_exempt  #不需要验证
    
    
    # 给CBV加装饰器
    from django.views import View
    from django.utils.decorators import method_decorator
    
    # 方式一:使用method_decorator
    class StudentsView(View):
    
        @method_decorator(csrf_exempt)
        def dispatch(self, request, *args, **kwargs):
            return super(StudentsView, self).dispatch(request, *args, **kwargs)
    
        def get(self, request, *args, **kwargs):
            print('get方法')
            return HttpResponse('GET')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST')
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT')
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE')
    
    #方式二:给类加装饰器,name标明要装饰的函数
    
    @method_decorator(csrf_exempt,name='dispatch')
    class ClassView(View):
    
        @method_decorator(csrf_exempt)
        def dispatch(self, request, *args, **kwargs):
            return super(ClassView, self).dispatch(request, *args, **kwargs)
    
        def get(self, request, *args, **kwargs):
            print('get方法')
            return HttpResponse('GET')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST')
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT')
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE')

    基于Django Rest Framework框架实现

    1. 认证和授权

    a. 用户url传入的token认证

    from django.conf.urls import url, include
    from web.viewsimport TestView
    
    urlpatterns = [
        url(r'^test/', TestView.as_view()),
    ]
    urls.py
    from django.shortcuts import render,HttpResponse
    from django.views import View
    from rest_framework.views import APIView
    from rest_framework.request import Request
    from rest_framework.authentication import BasicAuthentication
    from rest_framework import exceptions
    from app01.models import *
    
    class MyAuthentication(object):
        """
            用户认证,如果验证成功后返回元组: (用户,用户Token)
            :param request: 加工后的request
            :return: (user,auth)
                None,表示跳过该验证;
                    如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
                    self._authenticator = None
                    if api_settings.UNAUTHENTICATED_USER:
                        self.user = api_settings.UNAUTHENTICATED_USER()
                    else:
                        self.user = None
            
                    if api_settings.UNAUTHENTICATED_TOKEN:
                        self.auth = api_settings.UNAUTHENTICATED_TOKEN()
                    else:
                        self.auth = None
                (user,token)表示验证通过并设置用户名和Token;
                AuthenticationFailed异常
        """
        def authenticate(self,request):
            # request是加工过后对request,request._request是原来对request
            username = request._request.GET.get('username')
            password = request._request.GET.get('password')
            print(username,password)
            user = UserInfo.objects.filter(username=username,password=password).first()
            if not user:
                raise exceptions.AuthenticationFailed("验证失败")
            return (user,'auth')  #self.user, self.auth = user_auth_tuple
        def authenticate_header(self,val):
            pass
    
    
    class StudentsView(APIView):
        authentication_classes = [MyAuthentication,]
    
    
        def get(self, request, *args, **kwargs):
            # self.dispatch(request, *args, **kwargs)
            print(request.authenticators,"对象列表")
            #[<app01.views.MyAuthentication object at 0x105ca9b38>] 对象列表
            print(request._authenticator,"对象")
            #<app01.views.MyAuthentication object at 0x105ca9b38> 对象
    
            print(request.user.username)  #zhou
            print(request.auth)     #auth
            return HttpResponse("ok")
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST')
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT')
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE')
    views.py

    b. 登陆后生成token保存到数据库,访问时根据URL传入的token认证

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api/v1/auth', views.Authview.as_view()),
        url(r'^api/v1/order', views.Orderview.as_view()),
    
    ]
    urls.py
    from django.shortcuts import render,HttpResponse,render
    from rest_framework.views import APIView
    from rest_framework.request import Request
    from rest_framework import exceptions
    from rest_framework.authentication import BaseAuthentication
    from app01.models import *
    from django.http import JsonResponse
    
    
    def md5(user):
        """
        制作token
    
        """
        import hashlib
        import time
        stime = str(time.time())
        m = hashlib.md5(bytes(user,encoding="utf-8"))
        m.update(bytes(stime,encoding="utf-8"))
        return m.hexdigest()
    
    
    class Authview(APIView):
        """
        登陆校验,登陆成功后生成一个token存到数据库
        """
    
        def post(self,request):
            ret = {"code":1000,"msg":None}
            username = request._request.POST.get("username")
            pwd = request._request.POST.get("pwd")
            try:
                user = UserInfo.objects.filter(username=username,password=pwd).first()
                if not user:
                    ret["code"] = 1001
                    ret["msg"] = "用户名或密码错误"
                else:
                    token = md5(username)
                    #有则更新,没有则创建
                    UserToken.objects.update_or_create(user=user,defaults={"token":token})
                    ret["token"] = token
            except Exception as e:
                ret['code'] = 1002
                ret['msg'] = '请求出现错误:%s'%e
    
    
            return JsonResponse(ret)
    
    
    class Myauthenticat(BaseAuthentication):
        """
        自定义认证类,必须实现这两个方法
        """
        def authenticate(self,request):
            token = request._request.GET.get("token")
            if not token:
                raise exceptions.AuthenticationFailed("认证失败")
            obj = UserToken.objects.filter(token=token).first()
            if not obj:
                raise exceptions.AuthenticationFailed("验证码错误")
            return (obj.user,obj.token)
    
        def authenticate_header(self,val):
            pass
    
    
    class Orderview(APIView):
        # 认证
        authentication_classes=[Myauthenticat,]
    
        def get(self,request):
    
            print(request.user,request.auth) # UserInfo object ,b5c552a6c744818c8fe10d7f8554a4c6
            res = {"code":1000,"msg":None,"data":None}
            try:
    
                res["data"] = {"数据":123}
            except exceptions as e:
                res["msg"] = "请求出现错误:%s"%e
                res["code"] = 1002
            return JsonResponse(res)
    views.py

    c. 认证类必须继承BaseAuthentication

    1. 认证类,必须继承:from rest_framework.authentication import BaseAuthentication
    2. 其他认证类:BasicAuthentication
    

    d. 全局使用在配置文件中配置,单个CBV使用或者不用认证在类中重写 authentication_classes=[] 即可

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES':['appo1.utils.auth.Myauthenticat'],
        # 'UNAUTHENTICATED_USER':lambda :'匿名用户',  #定义是匿名用户时request.user的值
        'UNAUTHENTICATED_USER':None,  #定义是匿名用户时request.user的值  request.user = None
        'UNAUTHENTICATED_TOKEN':None  #定义是匿名用户时request.auth的值  request.auth = None
    }
    

    e. 三种返回值

    - 返回值:
    	- None,我不管了,下一认证来执行。
    	- raise exceptions.AuthenticationFailed('用户认证失败') # from rest_framework import exceptions
    	- (元素1,元素2)  # 元素1赋值给request.user; 元素2赋值给request.auth 

    f. 源码流程

    - 调用 dispatch
        - 封装request	
        - 调用 initial
    	 - 调用 perform_authentication  认证
    		- 调用request.user
                         - 获取定义的认证类(全局/局部),通过列表生成式创建对象列表。
                                - 循环调用对象的authenticate方法
    -如果通过认证返回一个元组,把第一个元素赋值给request.user,
                       第二个元素赋值给request.auth

      

    2. 权限认证

    a. 权限认证,继承 BasePermission实现 has_permission方法

    from rest_framework.permissions import BasePermission
    
    from rest_framework.permissions import BasePermission
    
    
    class SVIPPermission(BasePermission):
        message = "必须是SVIP才可以访问"  # 定义没权限时返回的信息
    
        def has_permission(self, request, view):
            # 这里的request是封装过后的request,并且通过认证后request.user和request.auth已经有值
            if request.user.user_type == 3:
                return True
            else:
                return False
    
        def has_object_permission(self, request, view, obj):
            pass
    
    #在需要的CBV中添加属性 permission_classes = [SVIPPermission,]
    views.py

    has_object_permission(self,request,view,obj):  对单个对象进行验证

    访问详细页时走RetrieveModelMixin里的get_obj() 方法 最终调用到has_object_permission方法

        # GenericAPIView中get_object时调用
        def has_object_permission(self, request, view, obj):
            """
            视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证
            Return `True` if permission is granted, `False` otherwise.
            :param request: 封装后的requrst 
            :param view: 视图函数对象
            :param obj: model对象
            :return: True有权限;False无权限
            """
            if request.user == "管理员":
                return True
    

      

    b. 全局使用配置,不需权限认证的类中重写 permission_classes = []  即可

    REST_FRAMEWORK = {
        #认证
        'DEFAULT_AUTHENTICATION_CLASSES':['app01.utils.auth.Myauthenticat'],
        # 'UNAUTHENTICATED_USER':lambda :'匿名用户',  #定义是匿名用户时request.user的值
        'UNAUTHENTICATED_USER':None,  #定义是匿名用户时request.user的值  request.user = None
        'UNAUTHENTICATED_TOKEN':None,  #定义是匿名用户时request.auth的值  request.auth = None
    
        #权限
        "DEFAULT_PERMISSION_CLASSES":['app01.utils.permission.SVIPPermission'],
    }  

    c. 返回值

       - 返回True 通过验证

       - 返回 False  不通过验证,message=‘xxx’ 可自定义错误信息

    d. 源码流程

    -调用dispatch
    -对原来对request进行封装,里面包含原来对request
    -调用inital进入验证
    -调用check_permissions方法
    -获取定义对权限类,全局或局部的,用列表生成式创建对象列表 -循环调用所有对定制权限类的has_permission方法 返回True通过,否则抛出异常

      

    3. 访问 次数/频率 限制

    a. 自定制的根据ip限制访问频率类

    from rest_framework.throttling import BaseThrottle
    import time
    
    res = {}
    
    class VisitThrottle(BaseThrottle):
        """
        每分钟小于三次
        """
        def __init__(self):
            self.history = None
        def allow_request(self, request, view):
            current_time = time.time()
            ip = request._request.META.get("REMOTE_ADDR")
            if ip not in res:
                res[ip] = [current_time,]
                return True
    
            history=res.get(ip)
            self.history = history
            while history and history[-1] < current_time-60:
                history.pop()
    
            if len(history)<3:
                history.insert(0,current_time)
                return True
    
        # return True    # 表示可以继续访问
        # return False # 表示访问频率太高,被限制
    
        def wait(self):
            """
            显示剩余事件
            """
            current_time = time.time()
            return 60 - (current_time - self.history[-1])
    
    
    class Orderview(APIView):
        
        #频率限制
        throttle_classes = [VisitThrottle,]
    
        def get(self, request):
            # self.dispatch()
            print(request.user, request.auth)  # UserInfo object ,b5c552a6c744818c8fe10d7f8554a4c6
            res = {"code": 1000, "msg": None, "data": None}
            try:
    
                res["data"] = {"数据": 123}
            except exceptions as e:
                res["msg"] = "请求出现错误:%s" % e
                res["code"] = 1002
            return JsonResponse(res)
    
        def throttled(self, request, wait):
            """
            访问次数被限制时,定制错误信息
            """
    
            class Throttled(exceptions.Throttled):
                default_detail = '请求被限制.'
                extra_detail_singular = '请 {wait} 秒之后再重试.'
                extra_detail_plural = '请 {wait} 秒之后再重试.'
    
            raise Throttled(wait)
    Views.py
    REST_FRAMEWORK = {
        #全局认证
        'DEFAULT_AUTHENTICATION_CLASSES':['app01.utils.auth.Myauthenticat'],
        # 'UNAUTHENTICATED_USER':lambda :'匿名用户',  #定义是匿名用户时request.user的值
        'UNAUTHENTICATED_USER':None,  #定义是匿名用户时request.user的值  request.user = None
        'UNAUTHENTICATED_TOKEN':None,  #定义是匿名用户时request.auth的值  request.auth = None
    
        #全局权限
        "DEFAULT_PERMISSION_CLASSES":['app01.utils.permission.SVIPPermission'],
    
        #全局控制频率
        'DEFAULT_THROTTLE_CLASSES':['app01.utils.throttle.VisitThrottle'],
        #内置类截流配置
        'DEFAULT_THROTTLE_RATES':{
            'zhou':'4/m', #每分钟4次
        }
    }
    settings.py

    b. 内置控制频率类(推荐使用)

    from rest_framework.throttling import SimpleRateThrottle
    
    
    class VisitThrottle(SimpleRateThrottle):
        scope = 'zhou'  # 在配置文件里设置的频率
    
        def get_cache_key(self, request, view):
            """
            :param request:封装后的request
            :param view:
            :return: 字典的键,用这个键作为限制的根据,例如限制一个ip的频率return self.get_ident(request)
                    限制一个账号的频率 return request.user.username
            """
            return self.get_ident(request)  # 得到IP
    
    
    class Orderview(APIView):
        # 频率控制
        throttle_classes = [VisitThrottle, ]
    
        def get(self, request):
            # self.dispatch()
            print(request.user, request.auth)  # UserInfo object ,b5c552a6c744818c8fe10d7f8554a4c6
            res = {"code": 1000, "msg": None, "data": None}
            try:
    
                res["data"] = {"数据": 123}
            except exceptions as e:
                res["msg"] = "请求出现错误:%s" % e
                res["code"] = 1002
            return JsonResponse(res)
    
        def throttled(self, request, wait):
            """
            访问次数被限制时,定制错误信息
            """
    
            class Throttled(exceptions.Throttled):
                default_detail = '请求被限制.'
                extra_detail_singular = '请 {wait} 秒之后再重试.'
                extra_detail_plural = '请 {wait} 秒之后再重试.'
    
            raise Throttled(wait)
    Views.py
    REST_FRAMEWORK = {
        #全局认证
        'DEFAULT_AUTHENTICATION_CLASSES':['app01.utils.auth.Myauthenticat'],
        # 'UNAUTHENTICATED_USER':lambda :'匿名用户',  #定义是匿名用户时request.user的值
        'UNAUTHENTICATED_USER':None,  #定义是匿名用户时request.user的值  request.user = None
        'UNAUTHENTICATED_TOKEN':None,  #定义是匿名用户时request.auth的值  request.auth = None
    
        #全局权限
        "DEFAULT_PERMISSION_CLASSES":['app01.utils.permission.SVIPPermission'],
    
        #全局控制频率
        'DEFAULT_THROTTLE_CLASSES':['app01.utils.throttle.VisitThrottle'],
        #内置类截流配置
        'DEFAULT_THROTTLE_RATES':{
            'zhou':'4/m', #每分钟4次
        }
    }
    settings.py

    c. 源码流程

    -调用dispatch
    -对原来对request进行封装,里面包含原来对request
    -调用inital进入验证
    -调用check_throttles方法
    -
    获取定义的节流类,全局或局部的,用列表生成式创建对象列表 -在这个方法里循环调用所有对定制限制频率类的allow_request方法 返回True通过,否则抛出异常,调用wait方法返回具体的剩余时间

      

    4. 版本

    a.  基于url的get传参方式,例如?version=v1

    自定义

        url(r'^users/', views.UserView.as_view(),name='users_list'),
    urls.py
    from django.urls import reverse
    
    from rest_framework.versioning import BaseVersioning
    
    
    class ParamVersion(BaseVersioning):
        """
        在URL的GET参数中获取版本信息
        """
        def determine_version(self, request, *args, **kwargs):
            #在URL获得版本version的值 query_params相当于_request.GET
            version = request.query_params.get("version")
            print(version,"version")
    
            return version  #返回版本号,在request.version就可以取到
    
    
    
    class UserView(APIView):
        versioning_class = ParamVersion  # 注意不要用列表
    
        def get(self,request,*args,**kwargs):
    
            # 获取版本
            print(request.version) #v1
            # 获取版本管理的类
            print(request.versioning_scheme) #<api.views.ParamVersion object at 0x105cb2860>
    
            # 反向生成URL,url需要参数时记得给参数
            reverse_url1 = request.versioning_scheme.reverse(viewname='users_list',request=request,kwargs={"version":"v2"})
            reverse_url2 =reverse('users_list',kwargs={'version':"v1"})
    
            print(reverse_url1) #http://127.0.0.1:8000/api/v2/users/
            print(reverse_url2) #/api/v1/users/
            return HttpResponse("用户列表")
    Views.py

    内置的类QueryParameterVersioning

        url(r'^users/', views.UserView.as_view(),name='users_list'),
    urls.py
    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    settings.py
    from rest_framework.versioning import QueryParameterVersioning
    class UserView(APIView):
        versioning_class = QueryParameterVersioning  # 注意不要用列表
    
        def get(self,request,*args,**kwargs):
    
            # 获取版本
            print(request.version) #v1
            # 获取版本管理的类
            print(request.versioning_scheme) #<rest_framework.versioning.QueryParameterVersioning object at 0x105ce92e8>
    
            # 反向生成URL,url需要参数时记得给参数
            reverse_url1 = request.versioning_scheme.reverse(viewname='users_list',request=request)
            reverse_url2 =reverse('users_list')
    
            print(reverse_url1) #http://127.0.0.1:8000/api/users/?version=v1
            print(reverse_url2) #/api/users/
            return HttpResponse("用户列表")
    Views.py

    b. 基于URL的正则方式  例如:api/v1/users/ (推荐使用)

    使用内置类URLPathVersioning

        url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view(), name='users_list'),
    
    #允许的版本有v1和v2
    urls.py
    from rest_framework.versioning import URLPathVersioning
    class UserView(APIView):
        versioning_class = URLPathVersioning  # 注意不要用列表
    
        def get(self,request,*args,**kwargs):
    
            # 获取版本
            print(request.version) #v2
            # 获取版本管理的类
            print(request.versioning_scheme) # <rest_framework.versioning.URLPathVersioning object at 0x105cf07b8>>
    
            # 自动反向生成URL
            reverse_url1 = request.versioning_scheme.reverse(viewname='users_list',request=request)
            #手动生成url,需要传参数
            reverse_url2 =reverse('users_list',kwargs={'version':'v1'})
    
            print(reverse_url1) #http://127.0.0.1:8000/api/v2/users/
            print(reverse_url2) #/api/v1/users/
            return HttpResponse("用户列表")
    Views.py

    如果想全局使用直接在配置文件内配置(推荐使用)

        #版本,基于URL的正则方式(全局)
        "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    

    c. 其他方式

    AcceptHeaderVersioning  #基于 accept 请求头方式
    NamespaceVersioning  #基于django路由系统的namespace
    HostNameVersioning  #基于主机名方法

    5. 解析器

    根据请求头 content-type 选择对应的解析器就请求体内容进行处理。

    request.POST中有值的条件

    1. 请求头要求:
    	Content-Type: application/x-www-form-urlencoded
    	PS: 如果请求头中的 Content-Type: application/x-www-form-urlencoded,request.POST中才有值(去request.body中解析数据)。
    2. 数据格式要求:
    	name=alex&age=18&gender=男
    		
    

    各种解析器:  

    仅处理请求头content-type为application/json的请求体  <JSONParser>  #发送json数据时仅request.data有值
    仅处理请求头content-type为application/x-www-form-urlencoded 的请求体<FormParser>  #发送表单数据时仅request.POST 和request.data 都有值
    仅处理请求头content-type为multipart/form-data(二进制数据)的请求体<MultiPartParser>  #request.data中有数据,如果是文件request.FILES中有
    仅上传文件<FileUploadParser>  #上传文件时request.FILES取值

    # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
    #导入 from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser 

    #配置 parser_classes = [JSONParser,FormParser,MultiPartParser,FileUploadParser]

    取值:

    request.data
    request.POST
    request.FILES 

    全局使用配置

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser',
            'rest_framework.parsers.FileUploadParser'
        ]
    
    }
    

    注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取

    6. 序列化

    序列化用于对用户请求数据进行验证和数据进行序列化。

    a. 基于serializers.Serializer自定义  

    from rest_framework import serializers
    
    class UserSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        username=serializers.CharField()
        password = serializers.CharField()
        user_type = serializers.CharField(source='get_user_type_display') #显示choices的中文
        group = serializers.CharField(source='group.title') #外健字段
        # roles = serializers.CharField(source='roles.all') #结果是一个queryset
        roles = serializers.SerializerMethodField()  #要先显示详细自定义,写一个 get_ 拼接的函数
    
        def get_roles(self,row):
            """
            :param row: 就是一个model类对象
            :return: 返回什么显示什么
            """
            queryset = row.roles.all()
            ret = []
            for obj in queryset:
                ret.append({"id":obj.pk,"title":obj.title})
            return ret
    
    
    
    
    class UserView(APIView):
    
        def get(self, request, *args, **kwargs):
    
            obj = UserInfo.objects.all()
            ser = UserSerializer(instance=obj,many=True)
    
            # ser.data 就是已经处理完的可序列化的数据
            return HttpResponse(json.dumps(ser.data))
    
        def post(self,request, *args, **kwargs):
    
    
            return HttpResponse("用户列表post")
    

    b. 基于serializers.SerializerMethodField 自动生成字段

    自己写类:

    class MyField(serializers.CharField):
    
        def to_representation(self, value):
            print(value,"value")
            # zhou value
            # yu value
            return value
    
    from rest_framework import serializers
    
    class UserSerializer(serializers.ModelSerializer):
        user_type = serializers.CharField(source='get_user_type_display')
        group = serializers.CharField(source='group.title')
        group_id = serializers.IntegerField(source='group.pk')
        roles = serializers.SerializerMethodField()
        name = MyField(source='username')
        class Meta:
            model=models.UserInfo
            # fields='__all__'  #处理所有的字段,但一些关联字段只显示id,要想详细的数据自己写
            fields=["id","name","user_type",'group',"group_id","roles"]
    
        def get_roles(self,row):
            """
            :param row: 就是一个model类对象
            :return: 返回什么显示什么
            """
            queryset = row.roles.all()
            ret = []
            for obj in queryset:
                ret.append({"id":obj.pk,"title":obj.title})
            return ret
    
    class UserView(APIView):
    
        def get(self, request, *args, **kwargs):
    
            obj = models.UserInfo.objects.all()
            ser = UserSerializer(many=True,instance=obj)
            # ser.data 就是已经处理完的可序列化的数据
    
            return HttpResponse(json.dumps(ser.data,ensure_ascii=False))
    
        def post(self,request, *args, **kwargs):
    
    
            return HttpResponse("用户列表post")
    Views.py
    [
        {
            "id": 1,
            "name": "zhou",
            "user_type": "SVIP",
            "group": "A组",
            "group_id": 1,
            "roles": [
                {
                    "title": "兔子",
                    "id": 1
                },
                {
                    "title": "萝莉",
                    "id": 2
                }
            ]
        },
        {
            "id": 2,
            "name": "yu",
            "user_type": "普通用户",
            "group": "B组",
            "group_id": 2,
            "roles": [
                {
                    "title": "兔子",
                    "id": 1
                }
            ]
        }
    ]
    返回的数据

    使用depth 自动序列化链表:

    from rest_framework import serializers
    
    class UserSerializer(serializers.ModelSerializer):
        user_type = serializers.CharField(source='get_user_type_display')
        class Meta:
            model=models.UserInfo
            # fields='__all__'  #处理所有的字段
            fields=["id","username","user_type",'group',"roles"]
            depth = 2  # 深度 官方建议0~10
    
    
    class UserView(APIView):
    
        def get(self, request, *args, **kwargs):
    
            obj = models.UserInfo.objects.all()
            ser = UserSerializer(many=True,instance=obj)
            # ser.data 就是已经处理完的可序列化的数据
    
            return HttpResponse(json.dumps(ser.data,ensure_ascii=False))
    
        def post(self,request, *args, **kwargs):
    
    
            return HttpResponse("用户列表post")
    Views.py
    [
        {
            "id": 1,
            "username": "zhou",
            "user_type": "SVIP",
            "group": {
                "id": 1,
                "title": "A组"
            },
            "roles": [
                {
                    "id": 1,
                    "title": "兔子"
                },
                {
                    "id": 2,
                    "title": "萝莉"
                }
            ]
        },
        {
            "id": 2,
            "username": "yu",
            "user_type": "普通用户",
            "group": {
                "id": 2,
                "title": "B组"
            },
            "roles": [
                {
                    "id": 1,
                    "title": "兔子"
                }
            ]
        }
    ]
    返回的数据

    生成URl:

    from django.conf.urls import url
    from api import views
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
    
        url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view(), name='users_list'),
        url(r'^(?P<version>[v1|v2]+)/group/(?P<group_id>d+)$', views.UserView.as_view(), name='group_detail'),
    
    ]
    urls.py
    from rest_framework import serializers
    
    class UserSerializer(serializers.ModelSerializer):
        user_type = serializers.CharField(source='get_user_type_display')
        # 生成URl,view_name是别名,lookup_field是查询依据的字段,lookup_url_kwarg是url里参数的名字
        group = serializers.HyperlinkedIdentityField(view_name='group_detail',lookup_field='group_id',lookup_url_kwarg='group_id')
        class Meta:
            model=models.UserInfo
            # fields='__all__'  #处理所有的字段
            fields=["id","username","user_type",'group',"roles"]
            depth = 2  # 深度 官方建议0~10
    
    
    
    class UserView(APIView):
    
        def get(self, request, *args, **kwargs):
    
            obj = models.UserInfo.objects.all()
            ser = UserSerializer(many=True,instance=obj,context={"request":request})
            #生成url时需要加上context={"request":request}
            # ser.data 就是已经处理完的可序列化的数据
    
            return HttpResponse(json.dumps(ser.data,ensure_ascii=False))
    
        def post(self,request, *args, **kwargs):
    
    
            return HttpResponse("用户列表post")
    views.py
    [
        {
            "id": 1,
            "username": "zhou",
            "user_type": "SVIP",
            "group": "http://127.0.0.1:8000/api/v2/group/1",
            "roles": [
                {
                    "id": 1,
                    "title": "兔子"
                },
                {
                    "id": 2,
                    "title": "萝莉"
                }
            ]
        },
        {
            "id": 2,
            "username": "yu",
            "user_type": "普通用户",
            "group": "http://127.0.0.1:8000/api/v2/group/2",
            "roles": [
                {
                    "id": 1,
                    "title": "兔子"
                }
            ]
        }
    ]
    返回的数据

    请求数据校验:

    class PasswordValidator(object):
        def __init__(self, base):
            self.base = str(base)
    
        def __call__(self, value):
            if not value.startswith(self.base):
                message = '标题必须以 %s 为开头。' % self.base
                raise serializers.ValidationError(message)
    
        def set_context(self, serializer_field):
            """
            This hook is called by the serializer instance,
            prior to the validation call being made.
            """
            # 执行验证之前调用,serializer_fields是当前字段对象
            pass
    
    class UserSerializerPOST(serializers.ModelSerializer):
        username=serializers.CharField(max_length=6,error_messages={"max_length":"最大长度为2"})
        password = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])
        class Meta:
            model = models.UserInfo
            fields='__all__'
            # fields=["username","password","roles"]
    
    
        def validate_username(self,value):
            print(value,"value") #value就是username的值
            from rest_framework import exceptions
            if not value.startswith("zhou"):
                raise exceptions.ValidationError("必须以zhou开头")
            else:
                return value
    
    
    class UserView(APIView):
    
    
        def post(self,request, *args, **kwargs):
    
            ser = UserSerializerPOST(data=request.data)
            if ser.is_valid():
                # 通过校验
                print(ser.validated_data,"validated_data")
                return HttpResponse("ok")
    
            else:
                print(ser.errors,"errors")
    
                return HttpResponse(json.dumps(ser.errors))
    

      

    7. 分页

    a. 根据页码进行分页,看第n页,每页显示n条数据

    from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
    
    
    class MyPageNumberPagination(PageNumberPagination):
        page_size = 2  # 每页显示的条数
        page_query_param = 'page'  # url里的参数key
        page_size_query_param = "size"  #可以指定每页显示多少条数据的参数 默认None
        max_page_size = 5  #每页显示数据的最大限制
    
    
    class UserSerializer(ModelSerializer):
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    class UserView(APIView):
    
    
        def get(self,request, *args, **kwargs):
            # 获取所有数据
            obj = models.Role.objects.all()
            # 创建分页器对象
            pg = MyPageNumberPagination()
            # 在数据库中获取分页的数据
            pager_roles = pg.paginate_queryset(queryset=obj,request=request,view=self)
            # 对数据序列化
            ser = UserSerializer(instance=pager_roles,many=True)
    
            return Response(ser.data)
    

      

    b. 位置和个数分页,在n个位置,往后查看n条

    from rest_framework.pagination import LimitOffsetPagination,CursorPagination
    
    
    class MyPageNumberPagination(LimitOffsetPagination):
    
        default_limit = 2 # 每页显示的条数
        limit_query_param = 'limit' # 每页查看多少条数据
        offset_query_param = 'offset'  #从第多少个开始
        max_limit = 5 # 每页显示数据的最大限制
    
    
    class UserSerializer(ModelSerializer):
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    class UserView(APIView):
    
    
        def get(self,request, *args, **kwargs):
            # 获取所有数据
            obj = models.Role.objects.all()
            # 创建分页器对象
            pg = MyPageNumberPagination()
            # 在数据库中获取分页的数据
            pager_roles = pg.paginate_queryset(queryset=obj,request=request,view=self)
            # 对数据序列化
            ser = UserSerializer(instance=pager_roles,many=True)
    
            return Response(ser.data)
    

      

    c. 游标分页,加密分页,显示上一页和下一页的URL

    from rest_framework.pagination import CursorPagination
    
    
    class MyPageNumberPagination(CursorPagination):
        cursor_query_param = 'cursor' # url里GET参数
        page_size = 5 # 每页显示几个
        ordering = 'id' # 按什么字段排序
    
    
    
    class UserSerializer(ModelSerializer):
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    class UserView(APIView):
    
    
        def get(self,request, *args, **kwargs):
            # 获取所有数据
            obj = models.Role.objects.all()
            # 创建分页器对象
            pg = MyPageNumberPagination()
            # 在数据库中获取分页的数据
            pager_roles = pg.paginate_queryset(queryset=obj,request=request,view=self)
            # 对数据序列化
            ser = UserSerializer(instance=pager_roles,many=True)
    
            # return Response(ser.data)
            return pg.get_paginated_response(ser.data) #使用这个方法显示上一页和下一页的url
    

    d. 可以在配置文件设置全局配置

    "PAGE_SIZE":2, #每页数据条数
    

      

    8. 视图

    a. GenericAPIView

    from rest_framework.response import Response
    from rest_framework.serializers import ModelSerializer
    from rest_framework.pagination import CursorPagination
    
    
    class MyPageNumberPagination(CursorPagination):
        """
        分页
        """
        cursor_query_param = 'cursor' # url里GET参数
        page_size = 5 # 每页显示几个
        ordering = 'id' # 按什么字段排序
    
    
    
    class UserSerializer(ModelSerializer):
        """
        序列化
        """
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    from rest_framework.generics import GenericAPIView
    
    class UserView(GenericAPIView):
        queryset = models.Role.objects.all()
        serializer_class = UserSerializer
        pagination_class = MyPageNumberPagination
    
    
        def get(self,request, *args, **kwargs):
            # 获取数据
            obj = self.get_queryset() # 相当于models.Role.objects.all()
    
            # 获取分页的数据
            pager_roles = self.paginate_queryset(obj)
            # 对数据序列化
            ser = self.get_serializer(instance=pager_roles,many=True)
    
            # return Response(ser.data)
            return self.get_paginated_response(ser.data) #使用这个方法显示上一页和下一页的url
    

      

    b. GenericViewSet

    from django.conf.urls import url
    from api import views
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
    
        url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view({"get":"list","post":"add"}), name='users_list'),
        url(r'^(?P<version>[v1|v2]+)/detail/(?P<pk>d+)/$', views.UserView.as_view({"get":"list","delete":"delete","put":"edit"}), name='xiangxi'),
    
    ]
    urls.py
    from rest_framework.response import Response
    from rest_framework.serializers import ModelSerializer
    from rest_framework.pagination import CursorPagination,PageNumberPagination
    
    
    class MyPageNumberPagination(PageNumberPagination):
        """
        分页
        """
        page_size = 2  # 每页显示的条数
        page_query_param = 'page'  # url里的参数key
        page_size_query_param = "size"  #可以指定每页显示多少条数据的参数 默认None
        max_page_size = 5  #每页显示数据的最大限制
    
    
    
    class UserSerializer(ModelSerializer):
        """
        序列化
        """
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    from rest_framework.generics import GenericAPIView
    from rest_framework.viewsets import GenericViewSet,ModelViewSet,ViewSetMixin
    from rest_framework.mixins import ListModelMixin,CreateModelMixin
    
    class UserView(GenericViewSet):
        queryset = models.Role.objects.all()
        serializer_class = UserSerializer
        pagination_class = MyPageNumberPagination
    
    
        def list(self,request, *args, **kwargs):
            if kwargs.get("pk"):
                return HttpResponse("详细")
            # 获取数据
            obj = self.get_queryset() # 相当于models.Role.objects.all()
    
            # 获取分页的数据
            pager_roles = self.paginate_queryset(obj)
            # 对数据序列化
            ser = self.get_serializer(instance=pager_roles,many=True)
    
            return Response(ser.data)
            # return self.get_paginated_response(ser.data) #使用这个方法显示上一页和下一页的url
    
    
        def add(self,request, *args, **kwargs):
    
            ser = UserSerializer(data=request.data)
            if ser.is_valid():
                # 通过校验
                print(ser.validated_data,"validated_data")
                return HttpResponse("ok")
    
            else:
                print(ser.errors,"errors")
    
                return HttpResponse(json.dumps(ser.errors))
    
        def delete(self, request, *args, **kwargs):
            print(kwargs["pk"],"pk")
            return HttpResponse("删除")
    
        def edit(self, request, *args, **kwargs):
    
            return HttpResponse("编辑")
    Views.py

    c. ModelViewSet(自定义URL)

    from django.conf.urls import url
    from api import views
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
    
        url(r'^(?P<version>[v1|v2]+)/users/$', views.UserView.as_view({"get":"list","post":"create"}), name='users_list'),
        url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>d+)/$', views.UserView.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'}), name='xiangxi'),
    
    ]
    urls.py
    from rest_framework.response import Response
    from rest_framework.serializers import ModelSerializer
    from rest_framework.pagination import PageNumberPagination
    
    
    class MyPageNumberPagination(PageNumberPagination):
        """
        分页
        """
        page_size = 2  # 每页显示的条数
        page_query_param = 'page'  # url里的参数key
        page_size_query_param = "size"  #可以指定每页显示多少条数据的参数 默认None
        max_page_size = 5  #每页显示数据的最大限制
    
    
    
    class UserSerializer(ModelSerializer):
        """
        序列化
        """
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    
    from rest_framework.viewsets import ModelViewSet
    
    class UserView(ModelViewSet):
        queryset = models.Role.objects.all()
        serializer_class = UserSerializer
    Views.py 

    d. ModelViewSet(rest framework路由)

    from django.conf.urls import url,include
    from rest_framework import routers
    from . import views
    
    
    router = routers.DefaultRouter()
    router.register(r'users', views.UserView)
    
    
    # Wire up our API using automatic URL routing.
    # Additionally, we include login URLs for the browsable API.
    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
    ]
    urls.py
    from rest_framework.response import Response
    from rest_framework.serializers import ModelSerializer
    from rest_framework.pagination import PageNumberPagination
    
    
    class MyPageNumberPagination(PageNumberPagination):
        """
        分页
        """
        page_size = 2  # 每页显示的条数
        page_query_param = 'page'  # url里的参数key
        page_size_query_param = "size"  #可以指定每页显示多少条数据的参数 默认None
        max_page_size = 5  #每页显示数据的最大限制
    
    
    
    class UserSerializer(ModelSerializer):
        """
        序列化
        """
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    
    from rest_framework.viewsets import ModelViewSet
    
    class UserView(ModelViewSet):
        queryset = models.Role.objects.all()
        serializer_class = UserSerializer
    Views.py

    视图继承关系

    9. 路由

    a. 自定义路由

    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())
    ]
    
    urls.py
    urls.py
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .. import models
    
    
    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            print(kwargs)
            print(self.renderer_classes)
            return Response('...')
    View.py

    b.半自动路由

    from django.conf.urls import url, include
    from web.views import s10_generic
    
    urlpatterns = [
        url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
        url(r'^test/(?P<pk>d+)/$', s10_generic.UserViewSet.as_view(
            {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
    ]
    urls.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.viewsets import ModelViewSet
    from rest_framework import serializers
    from .. import models
    
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class UserViewSet(ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = UserSerializer
    views.py

    c. 全自动路由

    from django.conf.urls import url,include
    from rest_framework import routers
    from . import views
    
    
    router = routers.DefaultRouter()
    router.register(r'users', views.UserView)
    
    
    # Wire up our API using automatic URL routing.
    # Additionally, we include login URLs for the browsable API.
    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
    ]
    from rest_framework.serializers import ModelSerializer
    
    class UserSerializer(ModelSerializer):
        """
        序列化
        """
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    
    from rest_framework.viewsets import ModelViewSet
    
    class UserView(ModelViewSet):
        queryset = models.Role.objects.all()
        serializer_class = UserSerializer
    View.py

    10. 渲染器

    from rest_framework.serializers import ModelSerializer
    
    class UserSerializer(ModelSerializer):
        """
        序列化
        """
        class Meta:
            model=models.Role
            fields="__all__"
    
    
    from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer  # JSON和浏览器的渲染器
    from rest_framework.viewsets import ModelViewSet
    
    class UserView(ModelViewSet):
        renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
        queryset = models.Role.objects.all()
        serializer_class = UserSerializer

    全局配置

    REST_FRAMEWORK = {
        #全局认证
        # 'DEFAULT_AUTHENTICATION_CLASSES':['app01.utils.auth.Myauthenticat'],
        # 'UNAUTHENTICATED_USER':lambda :'匿名用户',  #定义是匿名用户时request.user的值
        'UNAUTHENTICATED_USER':None,  #定义是匿名用户时request.user的值  request.user = None
        'UNAUTHENTICATED_TOKEN':None,  #定义是匿名用户时request.auth的值  request.auth = None
    
        #全局权限
        # "DEFAULT_PERMISSION_CLASSES":['app01.utils.permission.SVIPPermission'],
    
        #全局控制频率
        # 'DEFAULT_THROTTLE_CLASSES':['app01.utils.throttle.VisitThrottle'],
        #内置类截流配置
        'DEFAULT_THROTTLE_RATES':{
            'zhou':'4/m', #每分钟4次
        },
    
        #版本,基于get传参
        'DEFAULT_VERSION': 'v1',  # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
        'VERSION_PARAM': 'version', # URL中获取值的key
        #版本,基于URL的正则方式(全局)
        "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    
        #全局设置的解析器
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser',
            'rest_framework.parsers.FileUploadParser'
        ],
        # 分页
        "PAGE_SIZE":2, #每页数据条数
        # 渲染器
        "DEFAULT_RENDERER_CLASSES": [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        ]
    
    }

    错误处理

    'CourseView' should either include a `queryset` attribute, or override the `get_queryset()` method.

    'CourseView' should either include a `serializer_class` attribute, or override the `get_serializer_class()` method.

    原因:

    如果我们试图类,继承了:GenericAPIView 或 GenericAPIView的派生类,只要执行 get_queryset 时,可能会报错(queryset = None)
    
    如果我们试图类,继承了:GenericAPIView 或 GenericAPIView的派生类,只要执行 get_serializer 时,可能会报错(serializer_class = None)

    有时加上渲染器 BrowsableAPIRenderer浏览器访问时会报错,postman和api则不会

    分析原因:

      BrowsableAPIRenderer内部调用了get_queryset

    解决方法一: 

    加上属性queryset = ...  serializer_class = ...

    解决方法二:

    #继承APIView自己写,如果需要as_view里的对应关系可继承ViewSetMixin
    #from rest_framework.viewsets import GenericViewSet,ViewSetMixin
    #from rest_framework.views import APIView
    
    	url(r'^(?P<version>[v1|v2]+)/auth/$', views.AuthView.as_view()),
    	class MyView(APIView):
    		...
    		
    		
    	url(r'^(P<version[v1|v2]+)/course/$',views.CourseView.as_view({'get':'fun1'})),
    	class CourseView(ViewSetMixin,APIView):
    

      

  • 相关阅读:
    Hibernate初学
    表分区
    单列函数
    Oracle基础
    8.28
    SpringMVC
    SpringMVC 初级操作
    试题评测
    Mybatis

  • 原文地址:https://www.cnblogs.com/zhoujunhao/p/8510090.html
Copyright © 2011-2022 走看看