CBV源码分析

1概念:什么是cbv和fbv 已经什么是API

class bass View ---基于类的视图
function bass View ---基于函数的视图
API(Application Programming Interface)
API 就是应用程序编程接口。它是能用来操作组件、应用程序或者操作系统的一组函数

2什么是幂等性

现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就是使用RPC通信或者restful,既然是通信,那么就有可能再服务器处理完毕后返回结果的时候挂掉,这个时候用户端发现很久没有反应,那么就会多次点击按钮,这样请求有多次,那么处理数据的结果是否要统一呢?那是肯定的!尤其再支付场景。

幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品使用约支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条...

在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等。

在增删改查4个操作中,尤为注意就是增加或者修改,

查询对于结果是不会有改变的,

删除只会进行一次,用户多次点击产生的结果一样

修改在大多场景下结果一样

增加在重复提交的场景下会出现

那么如何设计接口才能做到幂等呢?

方法一、单次支付请求,也就是直接支付了,不需要额外的数据库操作了,这个时候发起异步请求创建一个唯一的ticketId,就是门票,这张门票只能使用一次就作废,具体步骤如下:

异步请求获取门票

调用支付,传入门票

根据门票ID查询此次操作是否存在,如果存在则表示该操作已经执行过,直接返回结果;如果不存在,支付扣款,保存结果

返回结果到客户端

如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的

方法二、分布式环境下各个服务相互调用

这边就要举例我们的系统了,我们支付的时候先要扣款,然后更新订单,这个地方就涉及到了订单服务以及支付服务了。

用户调用支付,扣款成功后,更新对应订单状态,然后再保存流水。

而在这个地方就没必要使用门票ticketId了,因为会比较闲的麻烦

(支付状态:未支付,已支付)

步骤:

1、查询订单支付状态

2、如果已经支付,直接返回结果

3、如果未支付,则支付扣款并且保存流水

4、返回支付结果

如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的

对于做过支付的朋友,幂等,也可以称之为冲正,保证客户端与服务端的交易一致性,避免多次扣款。

最后来看一下我们的订单流程,虽然不是很复杂,但是最后在支付环境是一定要实现幂等性的

什么是幂等性

用户对同一操作发起的一起请求和多次请求的结果一致,不回应为多次操作而产生副作用

3如何阅读源码

左侧工程栏--->设置图标-->点击--->show members(能看到py文件,类的方法)

4源码分析如下:

-def as_view 类方法
-def view:类方法内部,闭包函数定义:内层函数包含对外部作用域的引用
-python中一切皆对象:函数也是对象
-hasattr(self, 'get')--判断self类中是不是有该(get)方法
-反射 setattr(self,get,get_all):相当于把get函数,变成了get_all
-getattr(self, 'get'):拿到get函数的内存地址
- def view(request, *args, **kwargs):
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:谁的dispatch方法?写的cbv的那个c,视图中的那个视图类
#我这个类如果没有写dispatch,会执行View中的dispatch方法
return self.dispatch(request, *args, **kwargs)
-def dispatch(self, request, *args, **kwargs):
#request.method 前台请求的方法,转成了小写
#http_method_names View中定义的一个列表:是一堆请求方式
if request.method.lower() in self.http_method_names:
#getattr的第三个参数是默认值:self.http_method_not_allowed
#拿到get方法的内存地址
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
#get(request,*args, **kwargs)
return handler(request, *args, **kwargs) -def dispatch(self, request, *args, **kwargs):
#request.method 前台请求的方法,转成了小写
#http_method_names View中定义的一个列表:是一堆请求方式
if request.method.lower() in self.http_method_names:
#getattr的第三个参数是默认值:self.http_method_not_allowed
#拿到get方法的内存地址
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
#get(request,*args, **kwargs)
return handler(request, *args, **kwargs)

cbv源码分析详情在这儿

    总结:*******请求来了--->as_view---->view---->dispatch--->分发到不同的函数,执行函数,拿到结果,然后返回

resful规范

1什么是resful

REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”

REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态

所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性

对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

简而言之就是

1是一个规范
2面向资源编程:把网络中所有东西,想象成资源

2 resfuk API 设计(resful的十条规范)

  • API与用户的通信协议,总是使用HTTPs协议
  • -域名
    https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
    https://example.org/api/ API很简单
    例如写一个查询所有图书的api接口:https://api.example.com/books
    https://127.0.0.1/api/books

  • 版本:每个接口都应该有版本
    URL,如:https://api.example.com/v1/ https://127.0.0.1/api/v2/books(推荐用这种)
    请求头 跨域时,引发发送多次请求

  • 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
    https://api.example.com/v1/books
    https://api.example.com/v1/animals
    https://api.example.com/v1/employees
    不能这么写:
    -获取所有图书:https://127.0.0.1/api/get_all_books
    -新增一本书:https://127.0.0.1/api/add_book
    同一都用这个:
    https://api.example.com/v1/books

  • method
    GET :从服务器取出资源(一项或多项)
    POST :在服务器新建一个资源
    PUT :在服务器更新资源(客户端提供改变后的完整资源)
    PATCH :在服务器更新资源(客户端提供改变的属性)
    DELETE :从服务器删除资源

  • 过滤,通过在url上传参的形式传递搜索条件
    https://api.example.com/v1/zoos?limit=10:指定返回记录的数量

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

  • 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。

    GET /books:返回资源对象的列表(数组)
    GET /books/1:返回单个资源对象
    POST /books:返回新生成的资源对象 -新增,传数据,一旦新增完成,把新的资源对象返回
    PUT /books/1:返回完整的资源对象
    PATCH /books/1:返回完整的资源对象
    DELETE /books/1:返回一个空文档
  • Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API 方法,使得用户不查文档,也知道下一步应该做什么。
    {
    status:100
    msg:成功
    url:127.0.0.1/books/1
    }
    核心:返回结果中提供链接

参考自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

3基于Django写resful规范的接口

路由系统

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# as_view一定要加括号,as_view()哪里来的?从View中继承过来的
# as_view用类来调用的,它是一个类方法
# 猜:as_view这个方法执行完成以后,应该是个函数的内存地址
# 如果是get请求,会响应到类内部,执行get方法post请求,一样
# as_view 类方法,自动把自己传过来
url(r'^login/', views.Test.as_view()),
    url(r'^users/$', views.Users.as_view()),
url(r'^users2/$', views.user2),
 url(r'^books/(?P<pk>\d+)', views.Books.as_view()), ]

视图函数

import json

def  user2(request):
if request.method=='GET':
dic = {'status':200,'name': 'lqz2', 'age': 18}
return HttpResponse(json.dumps(dic))
elif request.method=='POST':
dic = {'status': 200, 'msg': '修改成功'}
return JsonResponse(dic) class Users(View):
def get(self, request):
dic = {'status':200,'name': 'lqz', 'age': 18}
return HttpResponse(json.dumps(dic)) def post(self, request):
dic = {'status': 200, 'msg': '修改成功'}
return JsonResponse(dic)

rest-framework之APIView

一:安装djangorestframework

方式一:pip3 install djangorestframework

方式二:pycharm图形化界面安装

方式三:pycharm命令行下安装(装在当前工程所用的解释器下)

2djangorestframework的APIView分析

@classmethod
def as_view(cls, **initkwargs):
"""
Store the original class on the view function. This allows us to discover information about the view when we do URL
reverse lookups. Used for breadcrumb generation.
"""
if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
def force_evaluation():
raise RuntimeError(
'Do not evaluate the `.queryset` attribute directly, '
'as the result will be cached and reused between requests. '
'Use `.all()` or call `.get_queryset()` instead.'
)
cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
return csrf_exempt(view) as_view方法

as_view

def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate? try:
self.initial(request, *args, **kwargs) # Get the appropriate handler method
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 dispatch

dispatch

def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request) return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
) initialize_request

initialize_request

def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request) initial方法(内部调用认证,权限和频率)

init方法(内部调用,权限和频率)

3djangorestframework的Request对象简单介绍

cbv+resful+APIView源码分析的更多相关文章

  1. CBV和APIView源码分析

    CBV源码分析 查看源码的方式,先查看自身,没有去找父类,父类没有就去找父父类... 自己定义的类 class Author(View): def get(self,request): back_di ...

  2. CBV源码分析+APIVIew源码分析

    {drf,resful,apiview,序列化组件,视图组件,认证组件,权限组件,频率组件,解析器,分页器,响应器,URL控制器,版本控制} 一.CBV源码分析准备工作: 新建一个Django项目 写 ...

  3. $Django cbv源码分析 djangorestframework框架之APIView源码分析

    1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...

  4. Restful规范-APIView源码分析

    目录 一.Restful规范 十条规范 二.drf的简单使用 三.APIView源码分析 CBV源码分析 APIView源码分析 一.Restful规范 Restful规范是一种web API接口的设 ...

  5. Django rest framework框架——APIview源码分析

    一.什么是rest REST其实是一种组织Web服务的架构,而并不是我们想象的那样是实现Web服务的一种新的技术,更没有要求一定要使用HTTP.其目标是为了创建具有良好扩展性的分布式系统. 可用一句话 ...

  6. drf的基本使用、APIView源码分析和CBV源码拓展

    cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...

  7. django Rest Framework----APIView 执行流程 APIView 源码分析

    在django—CBV源码分析中,我们是分析的from django.views import View下的执行流程,这篇博客我们介绍django Rest Framework下的APIView的源码 ...

  8. 探索drf执行流程之APIView源码分析

    Django REST framework 简介 现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式.而实现前后端分离是通过Django REST framework ...

  9. DRF中的APIView源码分析

    首先写一个简单的drf接口 from rest_framework.views import APIView from rest_framework.response import Response ...

随机推荐

  1. c#联网判断

    引用命名空间:sing System.Net.NetworkInformation; var address = "www.baidu.com"; Ping ping = null ...

  2. nagios 监控shell脚本

    线上应用shell脚本 参考链接:http://os.51cto.com/art/201301/376725.htm 0--各方面都正常,检查成功完成. 1--资源处于警告状态.某个地方不太妙. 2- ...

  3. You-Get 一键下载全网视频资源

      下载视频 无论是单纯的下载视频收藏,还是以便离线收看,都离不开“下载”,好的工具让你把注意力更好的放在视频的本身,而不用考虑要如何下载视频.下载视频从来不乏方法,之前也介绍了下载 Youtube ...

  4. codeforce 980B - Marlin(构造)

    Marlin time limit per test 1 second memory limit per test 256 megabytes input standard input output ...

  5. Python re模块与正则表达式的运用

    re模块 永远不要起一个py文件的名字,这个名字和你已知的模块同名 查找 findall():     匹配所有   每一项都是列表中的一个元素 语法 :   findall(正则判断条件,要判断字符 ...

  6. Java面向对象-访问控制权限

    Java面向对象-访问控制权限 Java中,可以通过一些Java关键字,来设置访问控制权限: 主要有 private(私有), package(包访问权限),protected(子类访问权限),pub ...

  7. sql 2008 权限角色控制

    Use Test --创建角色 create role rtt create user username for login username --将用户TestUser添加到TestRole角色中 ...

  8. 【原】Coursera—Andrew Ng机器学习—课程笔记 Lecture 6_Logistic Regression 逻辑回归

    Lecture6 Logistic Regression 逻辑回归 6.1 分类问题 Classification6.2 假设表示 Hypothesis Representation6.3 决策边界 ...

  9. 一个页面中内嵌页面 iframe元素

    iframe.html: <!DOCTYPE html><html lang="en"><head> <meta charset=&quo ...

  10. Navigator - BOM对象

    Navigator 对象 Navigator 对象包含有关浏览器的信息. 注释:没有应用于 navigator 对象的公开标准,不过所有浏览器都支持该对象. Navigator 对象集合 集合 描述 ...