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

    一、什么是restful?

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

    二、restful API设计(规范)

    一、API与用户的通信协议,总是使用HTTPS协议
    二、域名
        https:api.zhangjianping.com     尽量将API部署在专用的域名(不存在跨域问题)
        https:zhangjianping.org/api      简单的API
    三、版本
        URL:   https:api.zhangjianping.com/v1
        请求头           跨域时,引发发送多次请求
    四、路径,网络上的东西都是资源,均使用名词去表示
    五、method
        GET:从服务器取出资源(一项或者是多项)
        POST:在服务器新建一个资源
        PUT:在服务器更新资源(客户端提供改变后的完整资源)
        PATCH:在服务器更新资源(客户端提供改变的属性)
        DELETE:从服务器删除资源
    六、过滤
        通过在url上传参的形式传递搜索条件
    七、状态码
    八、错误处理
    九、返回结果
    十、Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
    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
    状态码附录

    三、基于Django实现

    路由系统:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^users/$',views.User.as_view()),
    ]

    CBV视图:

    from django.http import JsonResponse
    from django.views import View
    class User(View):
        def get(self,request,*args,**kwargs):
            result = {
                "status":True,
                "data":"response data"
            }
            return JsonResponse(result,status=200)
        def post(self,request,*args,**kwargs):
            result = {
                "status":True,
                "data":"response data"
            }
            return JsonResponse(result,status=200)

    四、基于Django-Rest-Framework框架实现

    1、基本流程

    路由系统:

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^test/$',views.TestView.as_view())
    ]

    CBV视图:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class TestView(APIView):
        def dispath(self,request,*args,**kwargs):
        """请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发不同的函数来处理"""
    return super().dispatch(request,*args,**kwargs) def get(self,request,*args,**kwargs): return Response("GET请求,响应内容") def post(self,request,*args,**kwargs): return Response("POST请求,响应内容") def put(self,request,*args,**kwargs): return Response("PUT请求,响应内容")

    以上这段代码就是rest framework框架的基本流程,重要的功能都是在APIView中的dispatch中触发的

    当你运行上段代码会报错:

    你使用的是restframework,但是模板用的却是Django的,所以报错在所难免,解决的办法就是在配置文件中注册

     2、认证和授权

    路由系统

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^test/$',views.TestView.as_view())
    ]

    CBV视图:

    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
    
    token_list = [
        "zhangjianping",           #可以授权的数据
    ]
    
    class TestAuthentication(BaseAuthentication):
        def authenticate(self, request):
            '''
            用户认证,认证成功后返回元组
            :param request:
            :return:
            '''
            val = request.query_params.get("token")    #get请求从网址栏获取到的数据
            if val not in token_list:                  #判断当前url是否可以授权访问
                raise exceptions.AuthenticationFailed("用户认证失败")
            return ("登录用户,","用户token")
        def authenticate_header(self, request):
            pass
    
    
    class TestView(APIView):
        '''
        调用这个函数的时候,会自动触发authentication_classes的运行,所以会先执行上边的类
        '''
        authentication_classes = [TestAuthentication,]
        permission_classes = []
    
    
        def get(self,request,*args,**kwargs):
            print("====request.user====",request.user)         #当前登录的用户
            print("====request.auth====",request.auth)         #获取到的用户token
            return Response("GET请求,响应内容")
    
        def post(self,request,*args,**kwargs):
            return Response("POST请求,响应内容")
    
        def put(self,request,*args,**kwargs):
            return Response("PUT请求,响应内容")

    3、用户登录

    路由系统:

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
      url(r'^auth/$',views.AuthView.as_view()),
    ]

    model表操作:

    from django.db import models
    
    class UserInfo(models.Model):
        username = models.CharField(max_length=16)
        password = models.CharField(max_length=16)
        token = models.CharField(max_length=64,null=True)

    CBV视图:

    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
    import time,hashlib
    from app01 import models
    
    class AuthView(APIView):
        authentication_classes = []
        def get(self,request):
            ret = {"code":1000,"msg":None}
            user = request.query_params.get("user")
            pwd = request.query_params.get("pwd")
            obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
            if not obj:    #如果没有获取到用户信息执行
                ret["code"] = 1001
                ret["msg"] = "用户名或密码错误"
                return Response(ret)
            ctime = time.time()   #得到一个时间戳
            key = "%s|%s"%(user,ctime)    #类似于加密盐
            m = hashlib.md5()
            m.update(key.encode("utf-8"))
            token = m.hexdigest()        #token经过MD5加密处理
            obj.token = token            #数据库的空字符串,颁发授权信息
            ret["token"] = token         #写入数据表
            return Response(ret)

     4、限制访问频率

     路由系统

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    from app02 import views as app02_view
    from app03 import views as app03_view
    urlpatterns = [
    rl(r'^salary/', app02_view.SalaryView.as_view()),
        url(r'^limit/', app03_view.LimitView.as_view()),
    ]
    #配置文件
    REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ # "app02.utils.MyAuthentication", ], 'DEFAULT_PERMISSION_CLASSES':[ ], 'DEFAULT_THROTTLE_RATES':{ 'wdp':'2/minute' #每分钟两次 } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': 'cache', 数据默认报错在缓存 } }
    #生写,自己实现            -----CBV视图
    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
    
    from rest_framework import exceptions
    
    RECORD = {
    
    }
    class MyThrottle(BaseThrottle):
        def allow_request(self,request,view):
            """
            # 返回False,限制
            # 返回True,通行
            :param request: 
            :param view: 
            :return: 
            """
            """
             a. 对匿名用户进行限制:每个用户1分钟允许访问10次
                - 获取用户IP request 1.1.1.1
            """
            import time
            ctime = time.time()          #获取当前时间
            ip = self.get_ident(request)        #获取IP
            if ip not in RECORD:         #IP没有在新建的那个字典
                RECORD[ip] = [ctime,]    #将当前的IP作为key,时间作为value列表
            else:
                # [4507862389234,3507862389234,2507862389234,1507862389234,]
                time_list = RECORD[ip]         #如果在的话获取IP时间列表
                while True:
                    val = time_list[-1]        #取出最后一个值
                    if (ctime-60) > val:       #如果当前的时间-60秒>取出的最后一个值
                        time_list.pop()        #就将这个值取出来
                    else:
                        break
                if len(time_list) > 10:    #一分钟访问次数超过10次,return False
                    return False
                time_list.insert(0,ctime)    #将当前时间插入到第一个位置
            return True
        def wait(self,request):
            """
            :return: 返回需要等待的时间
            """
            import time
            ctime = time.time()
            first_in_time = RECORD[self.get_ident(request)][-1]
            wt = 60 - (ctime - first_in_time)      #等待的时间
            return wt
    
    class LimitView(APIView):
        authentication_classes = []
        permission_classes = []
        throttle_classes=[MyThrottle,]
        def get(self,request,*args,**kwargs):
            # self.dispatch
            return Response('控制访问频率示例')
    
        def throttled(self, request, wait):
            """
            If request is throttled, determine what kind of exception to raise.
            """
    
            class MyThrottled(exceptions.Throttled):
                default_detail = '请求被限制.'
                extra_detail_singular = 'Expected available in {wait} second.'
                extra_detail_plural = '还需要再等待{wait}'
    
            raise MyThrottled(wait)

     CBV路由系统

    class MySimpleRateThrottle(SimpleRateThrottle):
        scope = "wdp"
    
        def get_cache_key(self, request, view):
            return self.get_ident(request)
    class LimitView(APIView):
        authentication_classes = []
        permission_classes = []
        throttle_classes=[MySimpleRateThrottle,]
        def get(self,request,*args,**kwargs):
            # self.dispatch
            return Response('控制访问频率示例')
    
        def throttled(self, request, wait):
            """
            If request is throttled, determine what kind of exception to raise.
            """
    
            class MyThrottled(exceptions.Throttled):
                default_detail = '请求被限制.'
                extra_detail_singular = 'Expected available in {wait} second.'
                extra_detail_plural = '还需要再等待{wait}'
    
            raise MyThrottled(wait)

    认证、权限+访问控制的实现

    from django.conf.urls import url
    from django.contrib import admin
    from app04 import views as app04_view
    
    urlpatterns = [
        url(r'^index/', app04_view.IndexView.as_view()),
        url(r'^manage/', app04_view.ManageView.as_view()),
    ]

    setting配置

    REST_FRAMEWORK = {
        'UNAUTHENTICATED_USER': None,
        'UNAUTHENTICATED_TOKEN': None,
        "DEFAULT_AUTHENTICATION_CLASSES": [    #认证控制
            # "app02.utils.MyAuthentication",
        ],
        'DEFAULT_PERMISSION_CLASSES':[     #权限控制
    
        ],
        'DEFAULT_THROTTLE_RATES':{
            'wdp_anon':'5/minute',       #匿名用户配置
            'wdp_user':'10/minute',      #正常用户配置
    
        }
    }
    
    CACHES = {                        #缓存配置
        'default': {
            'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'LOCATION': 'cache',
        }
    }

    CBV视图

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
    from rest_framework.authentication import BaseAuthentication
    from app02 import models
    
    class MyAuthentication(BaseAuthentication):
        """
        用户认证类,获取url传过来的数据
        """
        def authenticate(self, request):
            token = request.query_params.get('token')
            obj = models.UserInfo.objects.filter(token=token).first()
            if obj:
                return (obj.username,obj)
            return None
    
        def authenticate_header(self, request):
            pass
    
    class MyPermission(object):
        message = "无权访问"
        def has_permission(self,request,view):
            if request.user:
                return True
            return False
    
    class AdminPermission(object):
        message = "无权访问"
        def has_permission(self,request,view):
            if request.user == 'alex':
                return True
            return False
    
    
    class AnonThrottle(SimpleRateThrottle):
        """
        针对匿名用户的配置
        """
        scope = "wdp_anon"      #配置文件中的值
     
        def get_cache_key(self, request, view):
            # 返回None,表示我不限制
            # 登录用户我不管
            if request.user:          #正常登陆的用户不做限制
                return None
            # 匿名用户                #匿名用户做限制
            return self.get_ident(request)
    
    class UserThrottle(SimpleRateThrottle):
        """
        针对已经登陆的用户所做的配置
        """
        scope = "wdp_user"     #配置文件获取
    
        def get_cache_key(self, request, view):
            # 登录用户
            if request.user:
                return request.user
            # 匿名用户我不管
            return None
    
    
    # 无需登录就可以访问
    class IndexView(APIView):
        authentication_classes = [MyAuthentication,]          #用户认证
        permission_classes = []                               #无需登陆就可以访问的页面不需要权限的控制
        throttle_classes=[AnonThrottle,UserThrottle,]         #限流
        def get(self,request,*args,**kwargs):
            # self.dispatch
            return Response('无需登陆访问首页')
      
      def throttled(self, request, wait):
        """自定义返回的文本信息"""
      class MyThrottled(exceptions.Throttled):
      default_detail = '请求被限制.'
      extra_detail_singular = 'Expected available in {wait} second.'
      extra_detail_plural = '还需要再等待{wait}'
      raise MyThrottled(wait)

    # 需登录就可以访问 class ManageView(APIView): authentication_classes = [MyAuthentication,] permission_classes = [MyPermission,] #需要登陆访问的页面做了权限的控制 throttle_classes=[AnonThrottle,UserThrottle,] def get(self,request,*args,**kwargs): # self.dispatch return Response('需要登陆访问首页')

     5、版本限制

    URL做版本限制

    urlpatterns = [
        url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls')),
                ]
    urlpatterns = [
         url(r'^users/', views.UsersView.as_view(),name='u'),
                ]
    class UsersView(APIView):
        # 基于url传参
        # versioning_class = QueryParameterVersioning             get视图中直接采用request.version就可以取值
        # 基于URL http://127.0.0.1:8001/api/v2/users/
        # versioning_class = URLPathVersioning
        # 基于子域名 http://v1.luffy.com/users/
        # versioning_class = HostNameVersioning
        #上边的这些配置是基于局部配置,用的更多的是全局的配置,所以只介绍全局配置  

    def get(self,request,*args,**kwargs): self.dispatch print(request.version) # QueryParameterVersioning().detemiin_version() print(request.versioning_scheme) # QueryParameterVersioning() # 当前版本一样的URL url = request.versioning_scheme.reverse(viewname='u',request=request) print(url) # 当前版本不一样的URL from django.urls import reverse url = reverse(viewname='u',kwargs={'version':'v2'}) print(url) return Response('...')
    REST_FRAMEWORK = {
            'VERSION_PARAM':'version',          #固定的名字
            'DEFAULT_VERSION':'v1',              #默认版本号
            'ALLOWED_VERSIONS':['v1','v2'],       #可以使用的版本号
            'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning"     #版本由url控制
                }

    hostname做版本控制

    urlpatterns = [
         url(r'^api/', include('api.urls')),
                ]
    urlpatterns = [
         url(r'^users/', views.UsersView.as_view(),name='u'),
                ]
    class UsersView(APIView):
         def get(self,request,*args,**kwargs):
             self.dispatch
             print(request.version) # QueryParameterVersioning().detemiin_version()
             print(request.versioning_scheme) # QueryParameterVersioning()
    REST_FRAMEWORK = {
        'VERSION_PARAM':'version',
        'DEFAULT_VERSION':'v1',
        'ALLOWED_VERSIONS':['v1','v2'],
                    'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"     #根据域名做版本控制
                }
    根据hostname做版本限制需要配置域名,这里我们直接修改电脑的host文件做测试(Windows系统的 C:WindowsSystem32driversetc;mac本或者Linux的在
    # vim /etc/hosts) 直接做以下配置: 127.0.0.1 v1.qqq.com 127.0.0.1 v2.qqq.com

    6、解析器

    请求的数据进行解析:请求体进行解析。表示服务端可以解析的数据格式的种类。
         Content-Type: application/url-encoding.....
         request.body
         request.POST
                
         Content-Type: application/json.....
         request.body
         request.POST
    假如客户端发送的数据是:
         Content-Type: application/json
         '{"name":"alex","age":123}'
    那么服务端接受的是:
        读取客户端发送的Content-Type的值 application/json
           parser_classes = [JSONParser,]
           media_type_list = ['application/json',]
            
           如果客户端的Content-Type的值和 application/json 匹配:JSONParser处理数据
           如果客户端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser处理数据
    单视图:
    class UsersView(APIView):
         parser_classes = [JSONParser,]
                    
    全局配置:
    REST_FRAMEWORK = {
        'VERSION_PARAM':'version',
        'DEFAULT_VERSION':'v1',
        'ALLOWED_VERSIONS':['v1','v2'],
        # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
        'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
        'DEFAULT_PARSER_CLASSES':[
                  'rest_framework.parsers.JSONParser',            #解析jsonparser
                  'rest_framework.parsers.FormParser',            #解析formparser
                        ]
                    }

    7、序列化操作

    #需要导入的包和模块
    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.authentication import BasicAuthentication
    from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning,HostNameVersioning
    from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer
    from rest_framework.parsers import JSONParser,FormParser
    from rest_framework.request import Request
    from rest_framework import serializers
    from . import models                    #数据表

    数据库表

    from django.db import models
    
    # Create your models here.
    
    class Menu(models.Model):
        name = models.CharField(max_length=32)
    
    class Group(models.Model):
        title = models.CharField(max_length=32)
        mu = models.ForeignKey(to="Menu",default=1)
    
    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
    
        group = models.ForeignKey(to='Group')
        roles = models.ManyToManyField(to='Role')
    
    
    class Role(models.Model):
        name = models.CharField(max_length=32)

    a、基本操作

    class UsersSerializer(serializers.Serializer):
        name = serializers.CharField()
        pwd = serializers.CharField()
    
    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            # user_list = models.UserInfo.objects.all()
            # ser = UsersSerializer(instance=user_list,many=True)
            # return Response(ser.data)
    
            # 方式二之单对象
            user = models.UserInfo.objects.all().first()
            ser = UsersSerializer(instance=user, many=False)
            return Response(ser.data)

    b、跨表操作

    class UsersSerializer(serializers.Serializer):
        name = serializers.CharField()
        pwd = serializers.CharField()
        group_id = serializers.CharField()
        xxxx = serializers.CharField(source="group.title")
        x1 = serializers.CharField(source="group.mu.name")
    
    
    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            user_list = models.UserInfo.objects.all()
            ser = UsersSerializer(instance=user_list,many=True)
            return Response(ser.data)

    c、复杂的序列化

    操作一

    class MyCharField(serializers.CharField):
        def to_representation(self, value):
            data_list = []
            for row in value:
                data_list.append(row.name)
            return data_list
    
    class UsersSerializer(serializers.Serializer):
        name = serializers.CharField() # obj.name
        pwd = serializers.CharField()  # obj.pwd
        group_id = serializers.CharField() # obj.group_id
        xxxx = serializers.CharField(source="group.title") # obj.group.title
        x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
        # x2 = serializers.CharField(source="roles.all") # obj.mu.name
        x2 = MyCharField(source="roles.all") # obj.mu.name

    操作二

    class MyCharField(serializers.CharField):
        def to_representation(self, value):
            return {'id':value.pk, 'name':value.name}
    
    class UsersSerializer(serializers.Serializer):
        name = serializers.CharField() # obj.name
        pwd = serializers.CharField()  # obj.pwd
        group_id = serializers.CharField() # obj.group_id
        xxxx = serializers.CharField(source="group.title") # obj.group.title
        x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
        # x2 = serializers.CharField(source="roles.all") # obj.mu.name
        x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name

    操作三

    class UsersSerializer(serializers.Serializer):
        name = serializers.CharField() # obj.name
        pwd = serializers.CharField()  # obj.pwd
        group_id = serializers.CharField() # obj.group_id
        xxxx = serializers.CharField(source="group.title") # obj.group.title
        x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
        # x2 = serializers.CharField(source="roles.all") # obj.mu.name
        # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
        x2 = serializers.SerializerMethodField()
    
        def get_x2(self,obj):
            obj.roles.all()
            role_list = obj.roles.filter(id__gt=1)
            data_list = []
            for row in role_list:
                data_list.append({'pk':row.pk,'name':row.name})
            return data_list

    以上三种方式都是使用相同的视图

    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            user_list = models.UserInfo.objects.all()
            # [obj1,obj2,obj3]
            ser = UsersSerializer(instance=user_list,many=True)
            return Response(ser.data)

    d、基于model

    class UsersSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
            # fields = ['name', 'pwd','group']
            depth = 1
    
    
    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            user_list = models.UserInfo.objects.all()
            # [obj1,obj2,obj3]
            ser = UsersSerializer(instance=user_list,many=True)
            return Response(ser.data)

    e、生成url

    class UsersSerializer(serializers.ModelSerializer):
        group = serializers.HyperlinkedIdentityField(view_name='detail')
        class Meta:
            model = models.UserInfo
            fields = "__all__"
            fields = ['name', 'pwd','group']
            depth = 1
    
    
    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            user_list = models.UserInfo.objects.all()
            # [obj1,obj2,obj3]
            ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
            return Response(ser.data)

    f、全局生成url

    class UsersSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
            # fields = ['id','name','pwd']
    
    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            user_list = models.UserInfo.objects.all()
            # [obj1,obj2,obj3]
            ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
            return Response(ser.data)

    请求数据验证

    方式一

    class PasswordValidator(object):
        def __init__(self, base):
            self.base = base
    
        def __call__(self, value):
            if value != 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 UsersSerializer(serializers.Serializer):
            name = serializers.CharField(min_length=6)
            pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])

    方式二

    class PasswordValidator(object):
        def __init__(self, base):
            self.base = base
    
        def __call__(self, value):
            if value != 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 UsersSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
            extra_kwargs = {
                'name': {'min_length': 6},
                'pwd': {'validators': [PasswordValidator(666), ]}
            }

    使用:

    class UsersView(APIView):
        def get(self,request,*args,**kwargs):
            self.dispatch
            # 方式一:
            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
            # return Response(user_list)
    
            # 方式二之多对象
            user_list = models.UserInfo.objects.all()
            # [obj1,obj2,obj3]
            ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
            return Response(ser.data)
    
        def post(self,request,*args,**kwargs):
            ser = UsersSerializer(data=request.data)
            if ser.is_valid():
                print(ser.validated_data)
            else:
                print(ser.errors)
            return Response('...')

     8、分页

    a、基于limitoffsetpagination做分页

    class P1(LimitOffsetPagination):
        max_limit = 3
        default_limit = 2
        limit_query_param = 'limit'
        offset_query_param = 'offset'

    b、基于PageNumberPagination做分页

    class P2(PageNumberPagination):
        # 每页显示的数据条数
        max_page_size = 5
        page_size = 2
        page_size_query_param = 'size'
        # 页码
        page_query_param = 'page'

    c、基于CursorPagination做分页

    class P3(CursorPagination):
        cursor_query_param = 'cursor'
        page_size = 2
        ordering = 'id'

    需要用到的模块

    from django.shortcuts import render
    from rest_framework import views
    from rest_framework.response import Response
    from rest_framework.pagination import LimitOffsetPagination,PageNumberPagination,CursorPagination
    from api import models
    from api.serializers.index import IndexSerializer

    基于视图实现

    class IndexView(views.APIView):
        def get(self,request,*args,**kwargs):
            user_list = models.UserInfo.objects.all()            #查询到所有的数据
            p1 = P1()                                            #实例化显示的那个对象
            page_user_list = p1.paginate_queryset(queryset=user_list, request=request, view=self)     #经过处理后的数据列表
            ser = IndexSerializer(instance=page_user_list, many=True)       
            return Response(ser.data) # 不含上一页和下一页                 
            # return p1.get_paginated_response(ser.data) # 含上一页和下一页

    基于视图使用对象的方式实现

    class BaseResponse(object):
        def __init__(self,code=1000,data=None,error=None):
            self.code = code
            self.data = data
            self.error = error
    class IndexView(views.APIView):
        def get(self,request,*args,**kwargs):
            ret = BaseResponse()              #基于对象的形式展示
            try:
                user_list = models.UserInfo.objects.all()
                p1 = P1()
                page_user_list = p1.paginate_queryset(queryset=user_list,request=request,view=self)
                ser = IndexSerializer(instance=page_user_list,many=True)
                ret.data = ser.data         #给对象赋值
                ret.next = p1.get_next_link()      #上一页下一页链接
            except Exception as e:
                ret.code= 1001
                ret.error = 'xxxx错误'
            return Response(ret.__dict__)           #以字典的形式返回

     9、视图

    1. APIView

    class IndexView(views.APIView):
        def get(self, request, *args, **kwargs):
            user_list = models.UserInfo.objects.all()
            ser = IndexSerializer(instance=user_list,many=True)
            return Response(ser.data)

    2.GenericAPIView

    class IndexView(generics.GenericAPIView):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
        def get(self,request,*args,**kwargs):
            user_list = self.get_queryset()
            p1 = self.paginator
            data = p1.paginate_queryset(queryset=user_list,request=request,view=self)
            ser = self.get_serializer(instance=data,many=True)
            return p1.get_paginated_response(ser.data)

    3. GenericViewSet(ViewSetMixin, generics.GenericAPIView)

    路由修改
    urlpatterns = [
                    url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),]
                    
    from rest_framework.viewsets import GenericViewSet
    class IndexView(GenericViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
        def list(self,request,*args,**kwargs):
            print("这里是list请求")
            return Response("...")
        def retrieve(self,request,*args,**kwargs):
            print("这里是post请求")
            return Response("...")
        def create(self,request,*args,**kwargs):
            print("这里是put请求")
            return Response("...")
            
    
    
    
    
    自定义:
    
        增
            POST
            /users/
        删
            DELETE
            /users/1/
        改
            PUT
            /users/1/
            
            patch
            /users/1/
        查
            GET
            /users/ 
            GET
            /users/1/
                                
    urlpatterns = [
        url(r'^index/$', views.IndexView.as_view()),
        url(r'^index/(?P<pk>d+)$', views.IndexView.as_view({'get':'retrieve'})),
    ]
                                
    class IndexView(views.APIView):
    
        def get(self,request,*args,**kwargs):
            pk = kwargs.get('pk')
            if pk:
                pass # 获取单条信息
            else:
                pass # 获取列表信息
    
        def post(self,request,*args,**kwargs):
            pass
    
        def put(self,request,*args,**kwargs):
            pass
    
        def patch(self,request,*args,**kwargs):
            pass
    
        def delete(self,request,*args,**kwargs):
            pass

    4.ModelViewSet

    ModelViewSet(mixins.CreateModelMixin,
                mixins.RetrieveModelMixin,
                mixins.UpdateModelMixin,
                mixins.DestroyModelMixin,
                mixins.ListModelMixin,
                GenericViewSet)    
    视图:
    urlpatterns = [
        url(r'^user/$',views.IndexView.as_view({"get":"list","post":"create"})),
        url(r'^user/(?P<pk>d+)/$',views.IndexView.as_view({"get":"retrieve","delete":"destroy","put":"update","patch":"partial_update"}))
    ]
    from rest_framework.viewsets import ModelViewSet
    
    class IndexView(ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2        

    10、路由和渲染器

    第一类:
        # http://127.0.0.1:8000/api/v1/auth/
        url(r'^auth/$', views.AuthView.as_view()),
        # http://127.0.0.1:8000/api/v1/auth.json # 想要让页面显示json格式
        url(r'^auth.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
        # http://127.0.0.1:8000/api/v1/auth/1/
        url(r'^auth/(?P<pk>d+)/$', views.AuthView.as_view()),
        # http://127.0.0.1:8000/api/v1/auth/1.json
        url(r'^auth/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
        class AuthView(views.APIView):
    
            def get(self,request,*args,**kwargs):
                return Response('...')
    第二类:
        url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),
        url(r'^index/.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'list','post':'create'})),
        url(r'^index/(?P<pk>d+)/$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
        url(r'^index/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    
        class IndexView(viewsets.ModelViewSet):
            queryset = models.UserInfo.objects.all()
            serializer_class = IndexSerializer
            pagination_class = P2
    第三类: 
        router = DefaultRouter()
        router.register('index',views.IndexViewSet)
        urlpatterns = [
            url(r'^', include(router.urls)),
        ]
        
        
        class IndexViewSet(viewsets.ModelViewSet):
            queryset = models.UserInfo.objects.all()
            serializer_class = IndexSerializer
            pagination_class = P2
            
            
            
        class IndexSerializer(serializers.ModelSerializer):
            class Meta:
                model = models.UserInfo
                fields = "__all__"
    .渲染器
    renderer_classes = [JSONRenderer,BrowsableAPIRenderer]     #好看的页面默认返回的是这两个,如果只想返回json则    JSONRenderer    

     ##

    给query_set 新增一个扩展字段,并按照扩展字段进行排序(需要更新serializer,不需要更新model)

     类继承顺序

     

    未完待续。。。。

  • 相关阅读:
    sqlite表结构动态读取工具(Chole ORM框架)
    tomcat可以访问默认页面,但是无法访问webapp下的指定项目
    C#连接solr时提示 java内存异常 (jetty和tomcat哪个更High) java.lang.OutOfMemoryError
    Service Mesh
    Java 使用 UnixSocket 调用 Docker API
    ffmpeg-python 任意提取视频帧
    应用性能测试神器 Gatling,你用过吗?
    多语言应用性能监控系统:Elastic APM
    Ceph Plugin
    MAC iterm2 常用快捷键大全
  • 原文地址:https://www.cnblogs.com/52-qq/p/8417462.html
Copyright © 2011-2022 走看看