zoukankan      html  css  js  c++  java
  • DAY96-Rest Framework(一)-RESTful规范、APIView、序列化组件

    一、CBV源码分析

    1.基础配置

    # 路由
    from app01 import views
    
    urlpatterns = [
        url(r'^books/', views.Books.as_view()),
    ]
    
    # 视图
    from django.views import View
    class Books(View):
        def get(self,request):
            return HttpResponse('ok')
    

    2.执行顺序

    # 第一步
    # 请求通过url找到对应的类的as_view函数
    	#url(r'^books/', views.Books.as_view()),
        
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                # 将类所需的参数以及类赋值给self
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
    # 第三步,执行当前类的dispatch方法并返回
                return self.dispatch(request, *args, **kwargs)
    # 第二步,执行闭包函数view,把Books和路由的参数initkwargs传入
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view
    # 最后返回view的内存地址,相当于执行过后的dispatch方法的返回值
    # 也就是说,views.Books.as_view()是得到了返回的内存地址并加上()执行
    

    dispatch

    # 由第三步进入
    # 由于自定义的Books没有dispatch,会去继承的父类里找
    def dispatch(self, request, *args, **kwargs):
        # http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    	# 判断request带来的请求方式在不在列表里
        if request.method.lower() in self.http_method_names:
            # 如果在里面,就把当前的请求方式加上()执行并把返回值赋给handler
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
        	handler = self.http_method_not_allowed
        # 最后返回handler的返回值
        return handler(request, *args, **kwargs)
    

    总结

    1.Books.as_view

    2.as_view里的view

    3.view里的dispatch

    4.dispatch会判断你的请求方式并执行,最后返回结果response

    5.view返回dispatch的执行结果

    6.as_view返回view的内存地址

    7.最后在url里加上()执行

    二、resful规范

    1.什么是resful

    • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
    • 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
    • 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

    2.resful的10项规范

    • 总是使用HTTPS协议

    • 域名

      将API部署在专用域名(存在跨域问题):https://api.example.com

      简单API:https://www.example.com/api/

    • 版本控制

      https://www.example.com/api/v1(v2)

      请求头里携带版本号

    • 路径:由于是面向资源编程,后缀为名词

      https://www.example.com/api/v1/books

      https://www.example.com/api/v2/students

    • method:比如说书本,就只有books的路由,怎么区分增删查改的操作,就靠不同的请求

      GET :从服务器取出资源(一项或多项)

      POST :在服务器新建一个资源

      PUT :在服务器更新资源(客户端提供改变后的完整资源)

      PATCH :在服务器更新资源(客户端提供改变的属性)

      DELETE :从服务器删除资源

    • 条件过滤:可以通过url添加过滤条件

      https://www.example.com/api/v1/books?page=2&per_page=100:指定第几页,以及每页的记录数

    • 状态码

      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
      
    • 错误处理:应当返回错误信息

      {
      	'error':'xx错误',
      }
      
    • 返回结果

      GET:返回所有数据列表
      
      POST:返回新增的数据
      
      GET:返回单条数据
      #https://www.example.com/api/v1/books/1
           {id:1, 'name':'alex', 'salary':3000},
      
      PUT:更新,返回完整的资源对象
           {id:1, 'name':'alex', 'salary':3000},
      PATCH:更新,返回完整的资源对象
           {id:1, 'name':'alex', 'salary':3000},
      
      DELETE:删除
          返回空
      
    • Hypermedia API:即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

      {
          status:100
          msg:成功
          url:127.0.0.1/books/1
      }
      #核心:返回结果中提供链接
      

    三、drf(django rest framwork)框架

    1.安装

    它是一个app,要在咱的项目中用,只是快速的构建resful规范的接口

    pip3 install djangorestframework
    

    2.注册

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',
        'rest_framework'
    ]
    

    3.方法

    request.data:所有的Body体里的数据都以key:value放到了data里
    # 前台传来不同的数据格式,类型也不同,但使用方式是一样的
    # 前台传来JSON:request.data中的数据就是一个字典
    # 前台传来urlencode:request.data中的数据是一个QueryDict对象
    

    四、APIView源码分析

    1.基础配置

    # 路由
    from app01 import views
    
    urlpatterns = [
        url(r'^books/', views.Books.as_view()),
    ]
    
    # 视图
    from rest_framework.views import APIView
    from rest_framework.request import Request
    from rest_framework.response import Response
    class Books(APIView):
        def get(self,request):
            return HttpResponse('ok')
    

    2.执行顺序

    # 执行顺序大致与CBV的执行顺序相同,有改动
    def as_view(cls, **initkwargs):
        	# 调用父类APIView的as_view方法,APIView是继承View
            # APIView里没有as_view,也就是说,是调用View的as_view方法并把最终结果赋值给了view
            view = super(APIView, cls).as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
            # csrf_exempt局部禁用
            # 因为drf框架是不需要csrf认证的
            return csrf_exempt(view)
    
    # 第三步调用的dispatch从Books里找,没有就往上一层父类里找,APIView里有
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # APIView的dispatch调用APIView的initialize_request对request进一步的封装
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?
    	try:
            self.initial(request, *args, **kwargs)
    		if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
    
                response = handler(request, *args, **kwargs)
    
        except Exception as exc:
            response = self.handle_exception(exc)
    	self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    
    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)
        # 把原来的request以及所需参数传入,返回一个已经封装过的rest_framework中的Request对象
        return Request(
            request,
            parsers=self.get_parsers(),
    		# 认证
            authenticators=self.get_authenticators(),
            # 分页
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    

    总结

    1.Books(APIView).as_view (调用了View的as_view方法)

    2.as_view里的view

    3.view里的dispatch(从下往上找,APIView的dispatch)

    4.APIView的dispatch先对原先的request进行封装,然后判断请求方式并执行,最后返回结果response

    5.view返回dispatch的执行结果

    6.as_view返回view的内存地址

    7.最后在url里加上()执行

    3.补充

    hasattr(self, 'get')--判断self类中是不是有该(get)方法  
    setattr(self,get,get_all):相当于把get函数,变成了get_all 
    __setattr___方法:赋予值时触发
    getattr(self, 'get'):从self中拿到get函数的内存地址
    __getattr__方法: .的时候触发,也就是获得值时触发
    

    五、序列化

    方式一:for循环

    class Books(View):
        def get(self,request):
            books = models.Books.objects.all()
            ll = [{'name':book.name,'price':book.price} for book in books]
            return JsonResponse(ll,safe=False)
    

    方式二:django自带的序列化

    from django.core import serializers
    class Books(View):
        def get(self,request):
            books = models.Books.objects.all()
            ret = serializers.serialize('json',books)
            return HttpResponse(ret)
    

    方式三:drf提供的序列化组件

    from rest_framework.serializers import Serializer
    from rest_framework import serializers
    
    
    class BooksSerializer(Serializer):
        name = serializers.CharField(max_length=32)
        price = serializers.CharField(max_length=32)
    
    
    class Books(APIView):
        def get(self, request):
            books = models.Books.objects.all()
            # instance:要序列化的对象(可能是queryset,也可能是单个对象)    	 # many:如果是queryset---True,,如果是单个对象--False
            ret = BooksSerializer(instance=books,many=True)
            # 生成的是列表,需要转成JSON格式
    #[OrderedDict([('name', 'ab'), ('price', '12')]), 。。。。。]
            return JsonResponse(ret.data,safe=False)
    

    六、基于drf的增删查改

    class BooksSerializer(Serializer):
        name = serializers.CharField(max_length=32)
        price = serializers.CharField(max_length=32)
    
    
    class Books(APIView):
        # 获得所有获得一条
        def get(self, request, *args, **kwargs):
            id = kwargs.get('id')
            books = models.Books.objects.all()
            ret = BooksSerializer(books, many=True)
            if id:
                book = models.Books.objects.filter(pk=id).first()
                ret = BooksSerializer(book, many=False)
            return JsonResponse(ret.data, safe=False)
    
        # 创建数据
        def post(self, request, *args, **kwargs):
            name = request.POST.get('name')
            price = request.POST.get('price')
            book = models.Books.objects.create(name=name, price=price)
            ret = BooksSerializer(book, many=False)
            return JsonResponse(ret.data, safe=False)
    
        # 更新完整记录
        def put(self, request, *args, **kwargs):
            id = kwargs.get('id')
            name = request.data.get('name')
            price = request.data.get('price')
            if id:
                models.Books.objects.filter(pk=id).update(name=name, price=price)
                book = models.Books.objects.filter(pk=id).first()
                res = BooksSerializer(book, many=False)
                return JsonResponse(res.data, safe=False)
    
        # 更新一个字段
        def patch(self, request, *args, **kwargs):
            id = kwargs.get('id')
            price = request.data.get('price')
            if id:
                models.Books.objects.filter(pk=id).update(price=price)
                book = models.Books.objects.filter(pk=id).first()
                res = BooksSerializer(book, many=False)
                return JsonResponse(res.data, safe=False)
    
        # 删除
        def delete(self, request, *args, **kwargs):
            id = kwargs.get('id')
            if id:
                models.Books.objects.filter(pk=id).delete()
                book = models.Books.objects.filter(pk=id).first()
                res = BooksSerializer(book, many=False)
                return JsonResponse(res.data, safe=False)
    
  • 相关阅读:
    python---函数补充(变量传递),语句执行顺序(入栈顺序)
    python---基础知识回顾(十)进程和线程(多线程)
    python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法>
    FindMe
    Android Studio系列教程五--Gradle命令详解与导入第三方包
    Material Design
    asmack
    AlarmDemo-with-Database
    ZhuGongpu CloudX-for-Android
    SaundProgressBar
  • 原文地址:https://www.cnblogs.com/xvchengqi/p/10098753.html
Copyright © 2011-2022 走看看