目录
- 一、flask上下文源码分析(详见txt和图片)
-
- 1、具体流程以及源码分析
- 2、关于session以及请求扩展分析
- 二、flask-session的使用
- 三、数据库连接池
- 四、flask-script
一、flask上下文源码分析(详见txt和图片)
1、具体流程以及源码分析
请求上下文执行流程(ctx):
1 flask项目一启动,有6个全局变量
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))
2 请求来了 app()执行,调用Flask类的__call__()方法,内部执行了return self.wsgi_app(environ, start_response)
3 进入wsgi_app()
3.1 执行ctx = self.request_context(environ),返回RequestContext对象
def request_context(self,environ):
return RequestContext(self,environ)
进入RequestContext对象中
Class RequestContext(object):
def __init__(self,app,environ,request=None,session=None):
```
if request is None:
request = app.request_class(environ)
self.request = request
self.session = session
可以看出封装了当次请求的request对象以及session等
3.2 执行ctx.push()-->RequestContext对象的push方法
其中_request_ctx_stack.push(self)中的self是ctx对象
根据全局变量_request_ctx_stack = LocalStack(),进入LocalStack类中找push方法
def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, "stack", None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv
4 若在视图视图函数中使用request对象,比如print(request)
4.1 根据全局变量request = LocalProxy(partial(_lookup_req_object, "request"))可知,request对象的类是LocalProxy,并且使用了偏函数,提前传了request参数。request对象调用类的__repr__方法,obj = self._get_current_object(),执行self._get_current_object()方法,源码如下
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
4.2 偏函数源码分析
def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)
def top(self)
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
4.3 综上所述,print(request)就是打印当次请求的request对象的__str__;同理,如果在函数视图中print(request.method)实际就是打印出当次请求request的method属性
5 最后执行ctx.auto_pop(error),将ctx对象移除
2、关于session以及请求扩展分析
1 请求来了app对象类的open_session----> 执行wsgi_app()-->ctx = self.request_context(environ),执行ctx.push()---->
if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
2 请求走了app对象类的save_session----->-response = self.full_dispatch_request() 方法内部:执行了before_first_request,before_request,视图函数,after_request,savesession
self.full_dispatch_request()---->执行:self.finalize_request(rv)--->self.process_response(response)---->最后:self.session_interface.save_session(self, ctx.session, response)
before_first_request,before_request,after_request依次执行
-ctx:
-是:RequestContext对象:封装了request和session
-调用了:_request_ctx_stack.push(self)就是把:ctx放到了storage字典中
-app_ctx:
-是:AppContext(self) 对象:封装了当前的app和g
-调用 _app_ctx_stack.push(self) 就是把:app_ctx放到了storage字典中
专门用来存储用户信息的g对象,g的全称的为global
g对象在一次请求中的所有的代码的地方,都是可以使用的 (当次请求中传递一些数据)
g对象只对当次请求有效(当此请求内有效)
session:可以跨请求,该用户的多次请求中都可以使用
request和session就是代理对象,用的就是代理模式。本质是LocalProxy对象,代理到了request和session对象上。
二、flask-session的使用
1 由于原生的flask中session是加密后放到了cookie中
2 我们想保存到文件中,数据库中,redis(比较多)。。。
3 借助于第三方:flask-session
from flask import Flask,session
import redis
from flask_session import RedisSessionInterface
app = Flask(__name__)
conn = redis.Redis(host='127.0.0.1',port=6379)
app.session_interface = RedisSessionInterface(conn,key_prefix='lqz')
@app.route('/set_session')
def set_session():
session['age']='123'
return 'session写入了,写了age=123'
@app.route('/get_session')
def get_session():
s = session.get('age','取不到')
return '获取到的session是'+s
if __name__ == '__main__':
app.run()
from flask import Flask,session
from flask_session import Session
from redis import Redis
from datetime import timedelta
app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
app.config['SESSION_KEY_PREFIX'] = 'lqz'
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(days=31)
app.config.from_object('settings.Pro')
Session(app)
@app.route('/set_session')
def set_session():
session['name']='lqz'
return 'session写入了,写了name=lqz'
@app.route('/get_session')
def get_session():
s = session.get('name','取不到')
return '获取到的session是'+s
if __name__ == '__main__':
app.run()
from flask import Flask,session
from flask_session import Session
app = Flask(__name__)
app.config.from_object('settings.Pro')
Session(app)
@app.route('/set_session')
def set_session():
session['name']='lqz'
return 'session写入了,写了name=lqz'
@app.route('/get_session')
def get_session():
s = session.get('name','取不到')
return '获取到的session是'+s
if __name__ == '__main__':
app.run()
from redis import Redis
from datetime import timedelta
class Pro:
DEBUG = True
SESSION_TYPE = 'redis'
SESSION_REDIS = Redis(host='127.0.0.1',port='6379')
SESSION_KEY_PREFIX = 'lqz'
PERMANENT_SESSION_LIFETIME = timedelta(days=31)
三、数据库连接池
https://www.cnblogs.com/liuqingzheng/articles/9006055.html
1 传统方案存在的问题
conn = pymysql.Connect(host='127.0.0.1', user='root', password="123", database='luffy', port=3306)
curser = conn.cursor()
conn = pymysql.Connect(host='127.0.0.1', user='root', password="123", database='luffy', port=3306)
curser = conn.cursor()
2 使用数据库连接池
-pip3 install DButils
-两种模式:
第一种模式不用(为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接自动关闭)
第二种:创建一批连接到连接池,供所有线程共享使用,使用单例模式,pool就是单例
3 使用步骤
-第一步:新建sql_pool.py
import pymysql
from dbutils.pooled_db import PooledDB
POOL = PooledDB(
creator=pymysql,
maxconnections=6,
mincached=2,
maxcached=5,
maxshared=3,
blocking=True,
maxusage=None,
setsession=[],
ping=0,
host='127.0.0.1',
port=3306,
user='root',
password='123',
database='luffy',
charset='utf8'
)
-第二步:使用
from sql_pool import POOL
conn = POOL.connection()
curser = conn.cursor()
curser.execute('select * from luffy_order where id<2')
res=curser.fetchall()
print(res)
四、flask-script
1 django 运行项目 python manage.py runserver
2 借助于flask-script可以子定制命令
pip3 install flask-script
3 使用
-自带一个runserver
-自定制命令
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager=Manager(app)
@manager.command
def custom(arg):
"""
自定义命令
python manage.py custom 123
:param arg:
:return:
"""
print(arg)
@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
"""
自定义命令(-n也可以写成--name)
执行: python manage.py cmd -n lqz -u http://www.oldboyedu.com
执行: python manage.py cmd --name lqz --url http://www.oldboyedu.com
:param name:
:param url:
:return:
"""
print(name, url)
@app.route('/')
def index():
return '首页'
if __name__ == '__main__':
manager.run()