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)框架

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

pip3 install djangorestframework

四、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对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

总结

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 
__setatt___方法:赋予值时触发
getattr(self, 'get'):拿到get函数的内存地址
__getatt__方法r:获得值时触发

五、序列化

方式一: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)

猜你喜欢

转载自www.cnblogs.com/xvchengqi/p/10098753.html