Flask 配置、路由、模版、装饰器等
wsgi 找源码的流程
"""
1.程序启动,等待用户请求到来
app.run()
2.用户请求到来 app()
app.__call__ # return self.wsgi_app(environ, start_response)
"""
from flask import Flask
app = Flask(__name__)
@app.route('/index')
def index():
return 'hello world'
if __name__ == '__main__':
app.run()
# wsgi 找源码的流程
from werkzeug.serving import run_simple
from werkzeug.wrappers.response import Response
from werkzeug.wrappers import Response as ResponseBase
def func(environ, start_response):
print('请求来了')
response = Response('hello world')
# response = ResponseBase('hello world')
return response(environ, start_response)
if __name__ == '__main__':
run_simple('127.0.0.1', 5000, func)
追踪过程如下:
app.run()---> run_simple()中的self == app()---> __call__ ---> wsgi_app()---> full_dispatch_request()----> finalize_request(rv)----> make_response(rv)----> response_class()---> Response(ResponseBase)----> from werkzeug.wrappers import Response as ResponseBase
#### flask对象-静态文件的处理
```python
from flask import Flask,render_template
app = Flask(__name__,template_folder='templates',static_folder='static',static_url_path='/yy')
# static_folder 指定的静态文件所在的目录匹配目录名 此'static'特指 static_folder定义的目录
# static_url_path 指定静态文件访问匹配的路径代替static_folder目录名,类似别名
# 使用 static_url_path 和 {{ url_for('static',filename='img/haha.png')}} 可随意变更静态文件目录不用同时变量html
@app.route('/img')
def img():
return render_template('img.html')
if __name__ == '__main__':
app.run()
templates and static
templates and static
{# 建议 #}
配置文件
基于全局变量
from flask import Flask
app = Flask(__name__)
# 加载配置文件
app.config.from_object('config.settings') # 加载 ./config/settings.py 配置文件 settings.py 调用本地localsettings.py 配置,配置环境隔离,与敏感数据分离
print(app.config['DB_HOST'])
@app.route('/index')
def index():
return 'index'
if __name__ == '__main__':
app.run()
# ./config/settings.py
# 通用全局数据
DB_HOST = 'home.vimll.com'
DB_PORT = 'xxxxxx'
DB_USER = 'root'
DB_PWD = '111111'
# localsettings.py 本地测试或者敏感数据使用,本地环境配置覆盖上述全局通用配置
try:
from .localsettings import *
except ImportError:
pass
# ./config/localsettings.py
# localsettings.py 本地环境配置覆盖 settings.py内的全局通用配置
# 敏感数据放在正式环境本地的 localsettings.py
DB_HOST = '127.0.0.1'
DB_PORT = '3306'
DB_USER = 'root'
DB_PWD = '111111'
基于类的方式
from flask import Flask
app = Flask(__name__)
app.config.from_object('config.settings')
# 加载基础配置文件
app.config.from_object('config.settings.BaseSettings') # dev pro 配置包含BaseSettings
# 加载开发环境配置文件
app.config.from_object('config.settings.DevSettings')
# 加载生产环境配置文件
app.config.from_object('config.settings.ProSettings')
print(app.config['DB_HOST'])
print('BaseSettings', app.config['A'])
print('DevSettings', app.config['B'])
print('ProSettings', app.config['C'])
@app.route('/index')
def index():
return 'index'
if __name__ == '__main__':
app.run()
127.0.0.1
BaseSettings 1
DevSettings 2
ProSettings 3
* Serving Flask app '__main__'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
# 通用全局数据
DB_HOST = 'home.vimll.com'
DB_PORT = 'xxxxxx'
DB_USER = 'root'
DB_PWD = '111111'
# 基于类的配置文件
class BaseSettings(object):
"""通用基础配置文件"""
A = '1'
class DevSettings(BaseSettings):
"""开发环境配置文件"""
B = '2'
class ProSettings(BaseSettings):
"""生产环境配置文件"""
C = '3'
# localsettings.py 本地测试或者敏感数据使用,本地环境配置覆盖上述全局通用配置
try:
from .localsettings import *
except ImportError:
pass
if __name__ == '__main__':
obj = DevSettings()
print(obj.A)
路由系统
路由加载的两种方式:
- app.add_url_rule('/index', 'index', index)
- @app.route('/index')
路由加载的源码流程:
- 将url和函数打包成为 rule 对象
- 将rule对象添加到map对象中。
- app.url_map = map对象
from flask import Flask
app = Flask(__name__,template_folder='templates',static_folder='static',static_url_path='/static')
app.add_url_rule('/index', 'index', index)
# @app.route('/index') # self.add_url_rule(rule, endpoint, f, **options)
def index():
return '首页'
if __name__ == '__main__':
app.run()
动态路由
@app.route('/login')
def login():
return render_template('login.html')
@app.route('/login/')
def login(name):
print(type(name))
return render_template('login.html')
@app.route('/login/')
def login(name):
print(type(name))
return render_template('login.html')
正则表达式的路由
from werkzeug.routing import BaseConverter
from flask import Flask, render_template
app = Flask(__name__)
class RegConverter(BaseConverter):
def __init__(self, map, regex):
super().__init__(map)
self.regex = regex
# 对匹配到的值进行处理的函数(父类中有)
def to_python(self, value):
# return value 默认匹配得到的是字符串
return int(value) # 将其变成数值型
app.url_map.converters['regex'] = RegConverter
@app.route('/index/')
def index(x1):
print(x1, type(x1)) # 1
return "正则表达式的路由"
if __name__ == '__main__':
app.run()
视图
FBV
from flask import Flask, render_template
app = Flask(__name__, template_folder='templates',
static_folder='static', static_url_path='/static')
@app.route('/login')
def index():
return render_template('login.html')
if __name__ == '__main__':
app.run()
CBV
from flask import Flask,render_template,views
app = Flask(__name__,)
def test1(func):
def inner(*args,**kwargs):
print('before1')
result = func(*args,**kwargs)
print('after1')
return result
return inner
def test2(func):
def inner(*args,**kwargs):
print('before2')
result = func(*args,**kwargs)
print('after2')
return result
return inner
class UserView(views.MethodView):
methods = ['GET',"POST"]
decorators = [test1,test2]
def get(self):
print('get')
return 'get'
def post(self):
print('post')
return 'post'
app.add_url_rule('/user', view_func=UserView.as_view('user')) # endpoint
if __name__ == '__main__':
app.run()
* Serving Flask app '__main__'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [14/May/2024 17:24:43] "GET /user HTTP/1.1" 200 -
before2
before1
get
after1
after2
127.0.0.1 - - [14/May/2024 17:24:50] "POST /user HTTP/1.1" 200 -
before2
before1
post
after1
after2
模板
基本用法
flask比django更加接近Python
from flask import Flask,render_template
app = Flask(__name__,)
def func(arg):
return '你好' + arg
@app.route('/md')
def index():
nums = [11,222,33]
return render_template('md.html',nums=nums,f=func)
if __name__ == '__main__':
app.run()
Title
头
{% block content %} {% endblock %}
底
{% extends 'layout.html' %}
{% block content %}
MD
{% include 'form.html' %}
{{ f("waws") }}
{% endblock %}
定义全局模板方法
注意:在蓝图中注册的时候,应用返回只有本蓝图有效
from flask import Flask,render_template
app = Flask(__name__,)
@app.template_global() # {{ func("AAA") }}
def func(arg):
return arg
@app.template_filter() # {{ "AAA"|x1("-BBB") }} waws默认作为x1的第一个参数arg、在x1()中的参数使用name进行接收
def x1(arg,name):
return arg + name
@app.template_filter() # {{ "AAA"|x1("-BBB")|x2("-CCC") }} # AAA-BBB-CCC
def x2(arg,name):
return arg + name
@app.route('/md/hi')
def index():
return render_template('md_hi.html')
if __name__ == '__main__':
app.run()
特殊装饰器
特殊装饰器before_reques after_request
注意:before_after request可以在蓝图中定义,在蓝图中定义的话,作用域只在本蓝图。
from flask import Flask,render_template,request
app = Flask(__name__)
@app.before_request
def f1():
if request.path == '/login':
return
print('f1')
# return '123' # 如果有返回值,就不会往后继续执行
@app.after_request
def f10(response): # 注意在after_request中参数和返回值都是response
print('f10')
return response
@app.route('/index')
def index():
print('index')
return '首页'
@app.route('/login')
def login():
print('login')
return '登录'
if __name__ == '__main__':
app.run()
* Serving Flask app '__main__'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [15/May/2024 09:36:54] "GET /index HTTP/1.1" 200 -
f1
index
f10
127.0.0.1 - - [15/May/2024 09:37:12] "GET /login HTTP/1.1" 200 -
login
f10
多个特殊装饰器
from flask import Flask,render_template,request
app = Flask(__name__)
@app.before_request
def f1():
print('f1')
@app.before_request
def f2():
print('f2')
@app.after_request
def f10(response):
print('f10')
return response
@app.after_request
def f20(response):
print('f20')
return response
@app.route('/index')
def index():
print('index')
return '首页'
if __name__ == '__main__':
app.run()
app.__call__
* Serving Flask app '__main__'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [15/May/2024 09:47:22] "GET /index HTTP/1.1" 200 -
f1
f2
index
f20
f10
特殊装饰器的另一种使用方式
from flask import Flask,render_template
app = Flask(__name__,)
@app.route('/index')
def index():
print('index')
return '首页'
@app.before_request
def func():
print('xxx')
def x1():
print('X1')
app.before_request(x1)
if __name__ == '__main__':
app.run()