python3-开发进阶Flask的基础(2)
知识回顾
1、django 和flask区别?
最大的不同就是django请求相关的数据,通过参数一个一个传递过去的,而flask就是先把放在某个地方,然后去取,这个东西叫上下文管理
2、什么是wsgi?
web服务网关接口,wsgi就是一个协议和规范,实现该协议的模块:
-wsgiref
-werkzeug
实现其协议的模块本质上就是socket服务端用于接收用户请求,并处理,
一般web框架基于wsgi实现,这样实现关注点分离(通俗的说业务相关的,交给框架)
from werkzeug.wrappers import response from werkzeug.serving import run_simple def run_sever(environ,start_response): response=response('duoduo') # 封装一下 return response(environ,start_response) if __name__ == '__main__': run_simple('127.0.0.1',8000,run_sever)
3、flask提供的功能
配置文件
所有配置文件都在flask的对象.config中
flask的对象.config.from_object('引入类的路径') 小写也是生效的
应用: importlib 、getattr
django中间件
rest framework全局配置
session
加密后放置在用户浏览器的cookie中
流程:
请求到来--------》视图函数---------》请求结束
配置文件 生命周期31天 加密设置
路由
带参数的装饰器,自定义装饰器放下面
常用url,methods,endpoint 反向 url_for
视图
fbv
特殊装饰器
before_first_request
before_request
after_request
template_global()
template_filter()
errorhandler(404)
请求和响应
请求:request
响应:四种 字符串、render_template(模板)、redirect、jsonify (序列化)
加响应头就make_response
一、路由和视图
from flask import flask duo=flask(__name__) @duo.route('/index') def index(): print('index') return 'index' if __name__ == '__main__': duo.run()
我们今天开看看route的源码是什么样子的:
先不看中间的,发现定义阶段只是返回了 函数decorator的名字
1、限制性 decorator=duo.route('/index')
2、@decorator 这就和装饰器的原理一样,执行的话就把被装饰的函数名字传进去
3、上图中的f就是index函数,而rule就是(’/index‘)
这里就可以看出这个装饰器实质上就是:
duo.add_url_rule('/index', none, index)
我们注释掉装饰器,就用这一句代码跑跑看,脚本跑起来没问题!
我们继续看。add_url_rule里面的源码:
验证了之前说过的为什么endpoint默认情况等于函数名
获得参数都放到类似一个类,点开看看
果然是一个类
将路有关系添加到所有路由关系映射表
总结:
尽量不要让endpoint重名,如果重名函数一定要相同
参数:
rule, url规则 view_func, 视图函数名称 defaults=none, 默认值,当url中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数 endpoint=none, 名称,用于反向生成url,即: url_for('名称') methods=none, 允许的请求方式,如:["get","post"] strict_slashes=none, 对url最后的 / 符号是否严格要求, @app.route('/index',strict_slashes=false), 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可 @app.route('/index',strict_slashes=true) 仅访问 http://www.xx.com/index redirect_to=none, 重定向到指定地址 @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 或 def func(adapter, nid): return "/home/888" @app.route('/index/<int:nid>', redirect_to=func) subdomain=none, 子域名访问
cbv:
from flask import flask,views import functools def wrapper(func): @functools.wraps(func) def inner(*args,**kwargs): return func(*args,**kwargs) return inner duo=flask(__name__) class userview(views.methodview): methods = ['get'] #只允许get请求 decorators = [wrapper,] #加上要执行的装饰器的名字 def get(self,*args,**kwargs): return 'get' def post(self,*args,**kwargs): return 'post' duo.add_url_rule('/user',none,userview.as_view('uuuu')) if __name__ == '__main__': duo.run()
基本上大同小异
自定义正则:
from flask import flask,url_for duo=flask(__name__) #步骤一:定制类 from werkzeug.routing import baseconverter class regexconverter(baseconverter): ''' 自定义url匹配正则表达式 ''' def __init__(self,map,regex): super(regexconverter,self).__init__(map) self.regex=regex def to_python(self, value): ''' 路由匹配时,匹配成功过后传递给视图函数中参数的值 :param value: :return: ''' return int(value) def to_url(self, value): ''' 使用url_for反向生成url时,传递的参数经过该方法处理,返回值用于生成url中的参数 :param value: :return: ''' val=super(regexconverter,self).to_url(value) return val #完全可以不写 #步骤二:添加到转换器 duo.url_map.converters['reg']=regexconverter ''' 1、用户发送请求 2、flask内部进行正则匹配 3、调用to_python(正则匹配的结果)方法 4、to_python的返回值会交给视图函数的参数''' #步骤三:使用自定义正则 @duo.route('/index/<reg("\d+"):nid>') def index(nid): print(nid,type(nid)) print(url_for('index',nid=1)) return 'index' if __name__ == '__main__': duo.run()
二、session实现原理(源码)
flask
下面我们来一行行来验证上面猜想的:
self 是flask的对象duo,environ请求相关的原始数据
三、蓝图
目标:给开发者提供一个目录结构
1、首先创建一个和项目一样名字的文件夹,在文件夹中的__init__.py,先定义一个创建对象的函数
from flask import flask def create_app(): duo=flask(__name__) return duo
2、在项目一样名字的文件夹下,创建视图文件夹,在里面单独创建需求的功能视图
from flask import blueprint uc=blueprint('ac',__name__) @uc.route('/index/') def index(): return 'index'
3、建立他们之间的关系,在__init__导入生成的对象 uc,最后注册进去
from flask import flask from .views.user import uc def create_app(): duo=flask(__name__) duo.register_blueprint(uc,url_prefix='/duoduuo') #url_prefix适用版本控制 return duo #最后再写一个运行的脚本,
其他的功能:
自定义模板、静态文件
某一类url添加前缀
某一类url添加before_request
四、threading.local(和flask无任何关系)
先看一个简单事例:
import threading import time v=0 def task(i): global v v=i time.sleep(1) print(v) for i in range(10): t=threading.thread(target=task,args=(i,)) t.start() #结果都是9,最后一个修改覆盖所有,解决方法加锁
看一种解决方案:
import threading from threading import local #为每给线程创建一个独立空间来修改数据,使得线程对自己的空间中的数据进行操作(数据隔离) import time obj=local() def task(i): obj.duo=i time.sleep(1) print(obj.duo,i) for i in range(10): t=threading.thread(target=task,args=(i,)) t.start()
现在我们来考虑几个问题,
如何获取一个线程的唯一标记 ?
threading.get_ident() #跟linux进程pid类似
根据字典自定义一个类似于threading.local功能?
通过getattr,setattr 构建出加强版的threading.local功能!
import time import threading try: import greenlet #有就是协程,没有就是线程 get_ident=greenlet.getcurrent except exception as e: get_ident=threading.get_ident class local(object): dic={} def __getattr__(self, item): #self.xxx 触发执行 # print('getattr',item) ident=get_ident() if ident in self.dic: return self.dic[ident].get(item) return none def __setattr__(self, key, value): #self.xxx=123 触发执行 # print('setattr',key,value) ident=get_ident() if ident in self.dic: self.dic[ident][key]=value else: self.dic[ident]={key:value} obj=local() def task(i): obj.duo=i time.sleep(1) print(obj.duo,i) for i in range(10): t=threading.thread(target=task,args=(i,)) t.start()
后续还是有看源码的博客:
五、简述上下文管理
1、当请求到来时,在源码中wsgi_app 中 ctx 对象是requestcontext封装所有的对象和请求相关的原始数据,
这个对象就有request和session,在接下来的对session进行补充,将包含了request/session的ctx对象放到’神奇的地方‘
这个神奇的地方就是一个大字典,用线程或协程的唯一标识为key,
2、当视图函数使用的时候:
假使取一个request.method ,我们先导入 from flask import request ,根据当前线程取ctx对象,再取request,再取.method
3、当请求结束:
根据当前线程的唯一标记,将’神奇地方‘上的数据移除
上一篇: 三大主流手机浏览器测评 搜狗手机浏览器首推智能..
下一篇: HDU4576 Robot(概率)
推荐阅读
-
python3-开发进阶Flask的基础(3)
-
python3-开发进阶Django-debug-toolbar的配置和Django logging的配置
-
python3-开发进阶Flask的基础(5)
-
《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之8---Symbian,Windows Mobile,Palm,Linux,J2ME
-
Android开发利器之Data Binding Compiler V2 —— 搭建Android MVVM完全体的基础
-
python3-开发进阶Flask的基础(2)
-
python3-开发面试题(python)6.23基础篇(2)
-
浅谈PHP Extension的开发基础篇第1/2页
-
浅谈PHP Extension的开发基础篇第1/2页
-
ARM开发7.3.2 基础实训( 2 ) 单个按键的输入系统设计( 2)--LPC21XX