本文共 12360 字,大约阅读时间需要 41 分钟。
根据 "settings.DevelopmentConfig" 这个字符串形式的路径可以导入 "settings" 这个模块,并且可以找到模块中的 "DevelopmentConfig" 这个类,还可以根据 "dir" 找到 "DevelopmentConfig" 类中的大写的静态字段
import importlibpath = "settings.DevelopmentConfig"p, c = path.rsplit('.', maxsplit=1)m = importlib.import_module(p)cls = getattr(m, c)# 如何根据cls这个类获取到类中的静态字段for key in dir(cls): if key.isupper(): print(key, getattr(cls, key))
settings.py配置文件
import datetimeclass Config(object): TESTING = False PROPAGATE_EXCEPTIONS = None PRESERVE_CONTEXT_ON_EXCEPTION = None SECRET_KEY = None PERMANENT_SESSION_LIFETIME = datetime.timedelta(days=31) USE_X_SENDFILE = False SERVER_NAME = None APPLICATION_ROOT = '/' SESSION_COOKIE_NAME = 'session' SESSION_COOKIE_DOMAIN = None SESSION_COOKIE_PATH = None SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SECURE = False SESSION_COOKIE_SAMESITE = None SESSION_REFRESH_EACH_REQUEST = True MAX_CONTENT_LENGTH = None SEND_FILE_MAX_AGE_DEFAULT = datetime.timedelta(seconds=43200) TRAP_BAD_REQUEST_ERRORS = None TRAP_HTTP_EXCEPTIONS = False EXPLAIN_TEMPLATE_LOADING = False PREFERRED_URL_SCHEME = 'http' JSON_AS_ASCII = True JSON_SORT_KEYS = True JSONIFY_PRETTYPRINT_REGULAR = False JSONIFY_MIMETYPE = 'application/json' TEMPLATES_AUTO_RELOAD = None MAX_COOKIE_SIZE = 4093class ProductionConfig(Config): DEBUG = Falseclass DevelopmentConfig(Config): DEBUG = True
app.py 中可以使用按需修改后的 settings.py 中的配置信息
from flask import Flaskapp = Flask(__name__)app.config.from_object("settings.DevelopmentConfig") flask 中的路由url是依据带参数的装饰器写的
/<int:nid> 动态接收 id 值(int类型),可以传参/<nid> 未定义类型则默认接收 string 字符串类型from flask import Flaskfrom flask import url_for@app.route('/index/ ', methods=["GET", "POST"], endpoint="n1")# endpoint="n1" 相当于 django 路由系统 url 中的 name 起别名进行反向解析# 如果不写 endpoint="..." 则默认为:url_for("index") 视图函数名称 index# flask 路由反向解析用的是 url_for("n1")# 动态路由# '/ ' 动态接收 id 值(int类型),可以传参# '/ ' 未定义类型则默认接收 string 字符串类型def index(nid): print(url_for("n1", nid=1)) # /index/1 return "Index" import functoolsfrom flask import Flaskfrom flask import render_templatefrom flask import requestfrom flask import redirectfrom flask import sessionfrom flask import url_forfrom flask import Markupfrom flask import flashfrom flask import get_flashed_messagesapp = Flask(__name__)app.config.from_object("settings.DevelopmentConfig")# 模拟数据库中存储的用户STUDENT_DICT = { 1: {'name': '小明', 'age': 18, 'gender': '男'}, 2: {'name': '小李', 'age': 19, 'gender': '男'}, 3: {'name': '小花', 'age': 17, 'gender': '女'},}# def auth(func):# # '@functools.wraps(func)' 加上这个装饰器,可以避免被装饰的函数名变为'inner'# @functools.wraps(func)# def inner(*args, **kwargs):# if not session.get('user'):# return redirect(url_for('login'))# ret = func(*args, **kwargs)# return ret# return inner# 被'@app.before_request' 此装饰器装饰的业务逻辑会在所有视图函数执行之前执行# 跟 'django' 的 'process_request' 极为相似# 当被此装饰器装饰的业务逻辑有返回值时,整个flask框架中的所有视图函数都不会被执行# 直接显示 "被此装饰器装饰的业务逻辑的返回值"@app.before_requestdef auth(): if request.path == '/login': return None if session.get('user'): return None return redirect(url_for('login'))# 被此全局模板函数装饰器所装饰的业务逻辑,不需要借助任何视图函数传递此方法给模板,# 此方法会自动传递到需要应用此方法的模板中!# 模板只需要调用即可 {{global_template_func(1, 2)}} 即可在页面相应的位置显示出 3@app.template_global()def global_template_func(a, b): return a + b# {{ 1|filter_template_func(2, 3) }}# 页面显示 6@app.template_filter()def filter_template_func(a, b, c): return a + b + c@app.route('/login', methods=['GET', 'POST'])def login(): if request.method == 'POST': user = request.form.get('user') password = request.form.get('password') if user == 'aliang' and password == '007': session['user'] = user return redirect(url_for('index')) return render_template('login.html', error='用户名或密码错误!') return render_template('login.html')@app.route('/index')# @authdef index(): return render_template('index.html', stu_dic=STUDENT_DICT)@app.route('/delete/ ')# @authdef delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index'))@app.route('/detail/ ')# @authdef detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info)def func(arg): return arg + 1@app.route('/tpl')def tpl(): context = { 'users': ['小明', '小李', '小花'], # 'txt': " ", 'txt': Markup(" "), 'func': func } return render_template('tpl.html', **context)@app.route('/page1')def page1(): flash('存储临时数据') return "Session"@app.route('/page2')def page2(): flash_msg = get_flashed_messages() return flash_msgclass Middleware(object): def __init__(self, origin_wsgi_app): self.origin_wsgi_app = origin_wsgi_app def __call__(self, *args, **kwargs): # 在请求之前做相应的业务逻辑 ret = self.origin_wsgi_app(*args, **kwargs) # 在请求之后做相应的业务逻辑 return retif __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run() request.methodrequestd.argsrequest.formrequest.valuesrequesdt.cookiesrequest.headersrequest.pathrequest.full_pathrequest.script_rootrequest.urlrequest.base_urlrequest.url_rootrequest.host_urlrequest.hostrequest.filesobj = request.files['the_file_name']obj.save('/var/www/uploads/' + secure_filename(f.filename)) from flask import render_templatefrom flask import redirectfrom flask import jsonify# 以下4种返回的数据都是请求体,能不能将请求头也返回?可以封装!dic = {'k1': 'v1'}# return json.dumps(dic)# 相当于"django"中的JsonResponsereturn jsonify(dic)return "Index"return render_template("index.html")return redirect("/index") 定制返回的响应头
from flask import make_response# 将要返回的字符串"Index"封装到"make_response"中# 设置了响应体obj = make_response("Index")# 设置了响应头obj.headers['xxxx'] = 'oooo'# 设置cookie信息obj.set_cookie('key', 'value')return obj flask 模板渲染语法跟python语法极其相似
# app.py 文件中from flask import Markupdef func(arg): return arg + 1@app.route('/tpl')def tpl(): context = { 'users': ['小明', '小李', '小花'], # 'txt': "", 'txt': Markup(""), 'func': func } return render_template('tpl.html', **context) tpl.html 模板文件中
Title {{users.0}}{{users[0]}}{{txt}}{{txt|safe}}{{func(6)}}
被此全局模板函数装饰器所装饰的业务逻辑,不需要借助任何视图函数传递此方法给模板,
此方法会自动传递到需要应用此方法的模板中!模板只需要调用即可 {{global_template_func(1, 2)}} 即可在页面相应的位置显示出 3
# app.py 文件中@app.template_global()def global_template_func(a, b): return (a + b)
tpl.html 模板文件中
Title {{global_template_func(1, 2)}}
在模板中这样调用:{{ 1|filter_template_func(2, 3) }}
则在页面相应位置显示 6
# app.py 文件中@app.template_filter()def filter_template_func(a, b, c): return a + b + c
tpl.html 模板文件中
Title {{1|filter_template_func(2, 3)}} {% if 1|filter_template_func(2, 3) %}返回值为6{% else %}没有返回值{% endif %}
layout.html 模板文件中
Title {% block content%} {% endblock %}
tpl.html 继承 layout.html 模板文件
{% extends "layout.html"%}{% block content%} {{users.0}} {{users[0]}} {{txt}} {{txt|safe}} {{func(6)}}{% endblock %} nav.html 模板插件——>导航栏等插件
......
tpl.html 文件中
{% extends "layout.html"%}{% block content%} {% include "nav.html" %} {{users.0}} {{users[0]}} {{txt}} {{txt|safe}} {{func(6)}}{% endblock %} 适用于某个标签在整个页面上多次使用,可以按照宏定义的方式将此标签定义为一个代码块,在需要使用时直接调用即可!就不需要重写很多遍了!
模板宏定义的意思是可以在模板中定义一个代码块,代码块中可以按照python函数的定义方式去定义某个需要在特定时刻使用的标签
在需要显示此标签时,直接调用即可
如下:
{% macro tag(name, type='text', value='') %} 宏定义input标签
{% endmacro %}{{tag("user")}} django 中的session信息放在数据库中
flask 中的session信息经过加密之后保存在用户浏览器的cookie中
可以做权限管理
方法一:每个需要登录后才可以访问的页面所对应的视图函数中都查询一次是否有session信息
方法二:利用装饰器,在每个需要登录后才可以访问的页面所对应的视图函数上加装饰器,在走相应的视图函数之前先走装饰器中定义好的判断是否存在session信息的业务逻辑
装饰器(应用于被装饰的视图函数较少时)
import functoolsdef auth(func): @functools.wraps(func) # 加上这个装饰器,可以避免被装饰的函数名变为'inner' def inner(*args, **kwargs): if not session.get('user'): return redirect(url_for('login')) ret = func(*args, **kwargs) return ret return inner方法三:使用 '@app.before_request' 装饰器
被'@app.before_request' 此装饰器装饰的业务逻辑会在所有视图函数执行之前执行,跟 'django' 的 'process_request' 极为相似当被此装饰器装饰的业务逻辑有返回值时,整个flask框架中的所有视图函数都不会被执行,但所有被 '@app.after_request' 装饰器装饰的业务逻辑都会按照定义好的顺序倒序执行后直接显示 "被此装饰器装饰的业务逻辑的返回值"
当被此装饰器装饰的业务逻辑中返回 None 时,其他的视图才能正常执行
@app.before_requestdef auth(): if request.path == '/login': return None if session.get('user'): return None return redirect(url_for('login')) 原理:在session中存储一个数据,读取一次之后,通过pop将数据移除,可以达到存一次取一次即失效的效果!
flask中的session 信息是经过加密后保存在cookie中的,可以一直取,只要不过期,不手动删除,则session信息一直存在!
借助 flash 存储某一临时数据 & get_flashed_messages 获取临时数据,取一次即失效
from flask import flashfrom flask import get_flashed_messages@app.route('/page1')def page1(): flash('存储临时数据') return "Session"@app.route('/page2')def page2(): flash_msg = get_flashed_messages() return flash_msg# ['存储临时数据'] from flask import flashfrom flask import get_flashed_messages@app.route('/page1')def page1(): flash('存储临时数据1', '类别1') flash('存储临时数据2', '类别1') flash('存储临时数据3', '类别2') return "Session"@app.route('/page2')def page2(): flash_msg = get_flashed_messages(category_filter=['类别1']) return flash_msg# ['存储临时数据1', '存储临时数据2'] 跟django的中间件的实现有较大区别
flask 项目启动接口
if __name__ == '__main__': app.run()执行 run 方法后使得服务端处于监听状态
当有请求连接时,
try: run_simple(host, port, self, **options)
run_simple(host, port, self, **options)中的第三个参数self()即 flask 的实例化对象app()会执行类的__call__方法def __call__(self, environ, start_response): """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response)即在客户端请求连接时,基于flask框架的项目服务端会执行
__call__方法而我们知道中间件的作用就是在请求通过wsgi封装后经过路由匹配执行相应的视图函数再返回相应的模板页面之前做相应的业务逻辑,比如:发送某一请求访问特定的页面需要先登录之后才可以正常访问。
所以,flask 框架中的中间件即在
__call__方法执行之前做相关定义
flask 框架中的中间件即在
Flask类的__call__方法执行之前做相关定义
class Middleware(object): def __init__(self, origin_wsgi_app): self.origin_wsgi_app = origin_wsgi_app def __call__(self, *args, **kwargs): # 在请求之前做相应的业务逻辑 ret = self.origin_wsgi_app(*args, **kwargs) # 在请求之后做相应的业务逻辑 return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run()
类比于django的中间件
被'@app.before_first_request' 此装饰器装饰的业务逻辑会在 '@app.before_request' 装饰的业务逻辑之前仅执行一次
@app.before_first_requestdef excute_first(): print("项目启动之后第一次请求到来时,会在@app.before_request装饰的业务逻辑之前仅仅执行一次") 被'@app.before_request' 此装饰器装饰的业务逻辑会在所有视图函数执行之前执行,
跟 'django' 的 'process_request' 极为相似
当被此装饰器装饰的业务逻辑有返回值时,整个flask框架中的所有视图函数都不会被执行,但所有被 '@app.after_request' 装饰器装饰的业务逻辑都会按照定义顺序倒序执行后直接显示 "被此装饰器装饰的业务逻辑的返回值"
当被此装饰器装饰的业务逻辑没有返回值即返回 None 时,请求按流程正常执行!
@app.before_requestdef auth(): print('请先登录!') 被'@app.after_request' 此装饰器装饰的业务逻辑会在所有视图函数执行之后执行跟 'django' 的 'process_response' 极为相似
被装饰的业务逻辑必须要有返回值,若没有返回值,程序会报错
@app.after_requestdef after(response): print('请求已经得到响应!') return response 被此全局模板函数装饰器所装饰的业务逻辑,不需要借助任何视图函数传递此方法给模板,此方法会自动传递到需要应用此方法的模板中!
模板只需要调用即可 {{global_template_func(1, 2)}} 即可在页面相应的位置显示出 3
# app.py 文件中@app.template_global()def global_template_func(a, b): return (a + b)
tpl.html 模板文件中
Title {{global_template_func(1, 2)}}
在模板中这样调用:{{ 1|filter_template_func(2, 3) }}
则在页面相应位置显示 6
# app.py 文件中@app.template_filter()def filter_template_func(a, b, c): return a + b + c
tpl.html 模板文件中
Title {{1|filter_template_func(2, 3)}} {% if 1|filter_template_func(2, 3) %}返回值为6{% else %}没有返回值{% endif %}
被'@app.errorhandler(404)' 此装饰器装饰的业务逻辑可以自定义访问出错后的错误信息展示
@app.errorhandler(404)def not_found(error_msg): print(error_msg) return "访问的页面不存在!"
转载地址:http://eunuz.baihongyu.com/