一、简介
轻量级的框架,非常快速的就能把程序搭建起来
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。
“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。
默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。
- 和django的比较
django:无socket,依赖第三方模块wsgi,中间件,路由系统(CBV,FBV),视图函数,ORM。cookie,session,Admin,Form,缓存,信号,序列化。。
缺点:所有资源全部加载,造成一定资源的浪费
Flask:无socket,中间件(扩展),路由系统,视图(CBV)、第三方模块(依赖jinja2),cookie,自带组件session弱爆了
缺点:flask所有组件大部分都来自第三方,稳定性支持相对差些
- tornodo 龙卷风
异步IO非阻塞,原生websocket ==原生支持socket,实现并发,其它两大框架都需要第三方
里面组件太少,第三方支持的组件也太少
二、创建基础Flask应用
1. 安装
pip3 install flask
2. 创建项目
(1)方法一可通过pycharm直接创建,python会自动创建,自动下载flask【选择好解释器】
(2)方法二,手动创建
a、创建一个project,选好解释器,可以选择创建好的虚拟环境
b、创建一个py文件,如app.py
c、导入Flask模块,创建flask实例化,按其规则配好路由及写好视图,然后通过对象调用run方法即可启动flask应用
from flask import Flask # 实例化 app = Flask(__name__) # __name__ 当前对象,让解释器知道文件在那里 # 路由 @app.route("/") def index(): return "hello, welcome to flask……" if __name__ == '__main__': app.run(debug=True) # 默认不支持修改内容自动更新网页内容,加上debug后可以自动重启服务器,有错误会报错误页,想快些,可以ctrl+s来保存,快速重启服务
3. 创建静态文件目录,在项目下创建一个名子必须是static的目录,所有的图片等静态文件都放在里面
4. 创建模板存放目录,在项目下创建一个名字必须是templates的目录,所有的模板即html文件都放在里面
三、flask路由初始
@app.route('/', methods=['get', 'POST']) # 以装饰器的形式 # 写post,必须先写get,不然还是405,默认支持get,如果只是get请求可以不指定methods #如果发post请求时,为指定请求方法,则会405没有权限之报错
四、Response三剑客及发送文件&json数据
flask django
return 字符串 HttpResponse 返回字符串
render_template('index.html') render() 返回模板替换后的字符串
redirect() redirect() 重定向
from flask import Flask from flask import request # django里所有的request是当参数传,flask不是这样,他是将请求的数据放在request的一个容器里 from flask import redirect, render_template app = Flask(__name__) @app.route('/login') def sign_in(): return render_template('login.html') # render @app.route('/home', methods=['GET', 'POST']) # 写post,必须先写get,不然前端报错405表示访问页面没有权限,默认支持get,如果只是get请求可以不指定methods def home(): username = request.form.get('username', "") password = request.form.get('password', "") if username == "python" and password == "make_money": return redirect('/index') # redirect else: return "哪凉快,那呆着去 ……" @app.route('/index') def index(): return '欢迎来到北京开始程序员之旅……' # HttpResponse
比django多提供了两个方法:
from flask import send_file # 打开文件,并返回给浏览器 from flask import jsonify # 将信息序列化返回给浏览器,并在响应头中conten-type设置为application/json @app.route('/files') def file(): """发送文件""" return send_file('media/docker.mp4') # 发送文件,图片,视频,音频等, 视频显示不出来????? # return send_file('My_Flask.py') # @app.route('/text') def text(): """发送序列化格式数据""" dic = { "name": 'xxx'} # return dic # 前端无法接收,必须是str,tuple等,序列化后前端接到的也还是文本 return jsonify(dic, )
五、flask中的resquest
django中的request从请求封装后一直当参数传递,而flask中request是一个内存空间,容器,它存放了所有的请求数据,需要导入
from flask import request # django里所有的request是当参数传,flask不是这样,他是将请求的数据放在request的一个容器里
print(request) ## from 表单,使用www-urlencoded的content-type
# from 传文件需要定义
六、flask中的session组件
from flask import session app = Flask(__name__) app.secret_key = "自己设定的字符串" # 此字符串不能随意更改,不然所有的session失效,需要重新申请 # 设置session,必须先设置secret_key 为用户设置session都是登录认证成功后才设置的 session['key'] = ‘x'x'x'x'x’ # 获取session session.get('key') # 知识点回顾,字典获取两种方式一种中括号,一种get,没值时前面报错keyerror,后面返回空,后面的也可以设置默认值
flask中的session产生是由设置的secret_key 和设置的session值进行一个加密运算,从而得到一个字符串,被序列化后,然后将其发给浏览器,保存在本地cookie中!!!
它没有将session保存在服务器端,django是按传统的一样放在服务器端。
注意点:
七、jinja2模板语法
{
{变量}} 引用变量,非逻辑代码时使用
{
%%} 逻辑代码使用
# 逻辑判断及循环使用方法都同django { % if session %} { % endif %} { % for foo in session %} { % endfor %}
1. 模板传参取值
flask中传参给模板,发送的是一个单纯的字典时,key可随意定,在模板中引用,可点,可按字典两种方法取值
----视图
@app.route('/news') def news(): return render_template('jinja2.html', stu=STUDENT)
STUDENT = {'name': 'Old', 'age': 38, 'gender': '中'}
----html文件 <body> { { stu }} <table> <thead> <tr> <th>名字th> <th>年龄th> <th>genderth> tr> thead> <tbody> <tr> <td>{ { stu.0.name }}td> <td>{ { stu.0.get('age') }}td> <td>{ { stu.0['gender']}}td> tr> tbody> table> body>
效果图:
2. if和for逻辑中取值
后端将字典放在列表中传给前端,前端接到时一个列表中包着字典,取值同传一个单纯的字典一样,可以通过点,get,中括号取值
---view
@app.route('/news')
def news():
return render_template('jinja2.html', stu_list=STUDENT_LIST)
STUDENT_LIST = [
{'name': 'Old', 'age': 38, 'gender': '中'},
{'name': 'Boy', 'age': 73, 'gender': '男'},
{'name': 'EDU', 'age': 84, 'gender': '女'}
]
----html <table> <thead> <tr> <th>名字th> <th>年龄th> <th>genderth> tr> thead> <tbody> {% for dic in stu_list %} <tr> <td>{ { dic.name }}td> <td>{ { dic.get('age') }}td> <td>{ { dic['gender'] }}td> tr> {% endfor %} tbody> table>
3. 当字典里套字典传给前端时,通过点取值报错,只能通过另两种,但在前端还是可以用keys(),values(),items() 方法
注意:flask中前端模板使用方法,需要带括号,与django不一样
STUDENT_DICT = {
1: {'name': 'Old', 'age': 38, 'gender': '中'},
2: {'name': 'Boy', 'age': 73, 'gender': '男'},
3: {'name': 'EDU', 'age': 84, 'gender': '女'},
}
@app.route('/news')
def news():
return render_template('jinja2.html', stu_dict =STUDENT_DICT )
<table> <thead> <tr> <th>名字th> <th>年龄th> <th>genderth> tr> thead> <tbody> {% for key in stu_dict %} <tr> <td>{ { stu_dict[key].name }}td> <td>{ { stu_dict.get(key).get('age') }}td> {% if stu_dict[key].gender == '中' %} <td>非人类td> {% else %} <td>{ { stu_dict[key].gender }}td> {% endif %} tr> {% endfor %} tbody> table>
4. 继承
母版:同django一样,定义一个html如bash.html,引用{% extends 'bash.html' %}
块: 同django
组件: 同django
在模板中应用
{% extends 'bash.html' %}
{% block my_css %}
3333
{% endblock %}
{% include '4444.html' %}
返回标签
前端: 通过管道符 value|safe
后端: Markup(标签)
flask后台传标签,因为防止xss攻击,所以在前端渲染会是字符串
需要通过markup一下,同django中的safe
----后端返回安全标签方法
from flask import Markup @app.route('/filter') def filters(): a = '<a href="http://www.baidu.com">百度a>' a = Markup(a) # 通过该方法告诉浏览器这是一个安全的标签 return render_template('3333.html', a=a)
注: 0.9 以前的版本,在模板中应用不存在的变量报错,后面的不报错!!!
八、扩展:
1、 flask中通过手写装饰器联合session如何验证用户登录状态?
from flask import Flask from flask import session from flask import render_template, redirect, request from functools import wraps """ 需求:访问某些页面需要用户登录后才能查看 方案:通过装饰器联合session校验用户登录状态 逻辑: 1、用户登录认证后,为用户创建唯一sessionid保存用户信息,响应时传给浏览器保存在本地cookie中,下次访问时自动带上session 2、在需要验证的视图上加上装饰器,用户请求路由匹配视图后,会先走装饰器 3、在装饰器中,获取用户预访问页面url,保存下来next_url=request.full_path,以备登录后自动跳转到该页面 获取用户的携带的session,如果携带了就表示用户处于登录状态 如果未携带就表示未登录,通过重定向让用户去登录。 此时为了能够登录后跳转用户需求页面,进行url拼接,如:"/login?nexturl={}".format(next_url) 4、用户登录认证后,从访问url中获取nexturl,然后跳转到nexturl,如果用户是直接登录的,就自动跳转到主页 """ app = Flask(__name__) app.secret_key = "first_goal" # 随机字符串 def check_login(f): @wraps(f) # 装饰后print(f.__name__)时打印的是功能函数名而不是inner def inner(*args, **kwargs): next_url = request.full_path # 不含主机位 if session.get('u_info', ""): ret = f(*args, **kwargs) return ret return redirect('/login?next_url={}'.format(next_url)) return inner @app.route('/login', methods=['get', 'POST']) def login(): if request.method == 'POST': username = request.form.get('username', "") password = request.form.get('password', "") if username == "python" and password == "123456": next_url = request.args.get('next_url', '/') session['u_info'] = username return redirect(next_url, ) return render_template('login.html') @app.route('/', methods=['get']) def index(): return "欢迎光临……" @app.route('/news') @check_login def news(): return render_template('jinja2.html', stu=STUDENT, stu_list=STUDENT_LIST, stu_dict=STUDENT_DICT)
注意:装饰器必须是最下面的一个被装饰的,不然装饰器失效
上面的缺陷是,如果需要装饰的视图过多,就比较麻烦,还有就是,如果对多个视图装饰后,如果在inner函数上不进行@warp(func_name)的话,flask启动时会进行报错,如下图
出现上面的报错原因是:
视图创建,未指定endpoint时,在route初始化时,将endpoint的值设置为视图函数的名字
因装饰器的原因,被装饰的函数,函数名变了,变成了inner,如果多个视图被同一个装饰器装饰,就会导致所有的视图函数名都成inner了,这就导致endpoint名都一样了,
而endpoit又可以作为视图的反向解析,这时就会导致无法找到对应的视图,故endpoint不能一样,从而在被同一个装饰器装饰,endpoint就需要赋值才能解决上面的报错。
九、Flask的参数及对app的配置
Flask 是一个非常灵活且短小精干的web框架 , 那么灵活性从什么地方体现呢?
有一个神奇的东西叫 Flask配置 , 这个东西怎么用呢? 它能给我们带来怎么样的方便呢?
首先展示一下:
from flask import Flask app = Flask(__name__) # type:Flask app.config["DEBUG"] = True
这句 app.config["DEBUG"] = True 可以实现的功能可刺激了
代码只要发生改动,自动重启Flask程序(app.run)
在控制台打印的信息非常全面
以上两个功能就是传说中的 DEBUG 模式(调试模式)
Flask的配置就是在 app.config 中添加一个键值对,但是你存进去的键必须是config中应该存在的,如果不再存在的话,它会默认无用,就这么放着
config中有多少有用的key 呢?
{ 'DEBUG': False, # 是否开启Debug模式 'TESTING': False, # 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, # 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True 'PRESERVE_CONTEXT_ON_EXCEPTION': None, # 一两句话说不清楚,一般不用它 'SECRET_KEY': None, # 之前遇到过,在启用Session的时候,一定要有它 'PERMANENT_SESSION_LIFETIME': 31, # days , Session的生命周期(天)默认31天 'USE_X_SENDFILE': False, # 是否弃用 x_sendfile 'LOGGER_NAME': None, # 日志记录器的名称 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, # 服务访问域名 'APPLICATION_ROOT': None, # 项目的完整路径 'SESSION_COOKIE_NAME': 'session', # 在cookies中存放session加密字符串的名字 'SESSION_COOKIE_DOMAIN': None, # 在哪个域名下会产生session记录在cookies中 'SESSION_COOKIE_PATH': None, # cookies的路径 'SESSION_COOKIE_HTTPONLY': True, # 控制 cookie 是否应被设置 httponly 的标志, 'SESSION_COOKIE_SECURE': False, # 控制 cookie 是否应被设置安全标志 'SESSION_REFRESH_EACH_REQUEST': True, # 这个标志控制永久会话如何刷新 'MAX_CONTENT_LENGTH': None, # 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码 'SEND_FILE_MAX_AGE_DEFAULT': 12, # hours 默认缓存控制的最大期限 'TRAP_BAD_REQUEST_ERRORS': False, # 如果这个值被设置为 True ,Flask不会执行 HTTP 异常的错误处理,而是像对待其它异常一样, # 通过异常栈让它冒泡地抛出。这对于需要找出 HTTP 异常源头的可怕调试情形是有用的。 'TRAP_HTTP_EXCEPTIONS': False, # Werkzeug 处理请求中的特定数据的内部数据结构会抛出同样也是“错误的请求”异常的特殊的 key errors 。 # 同样地,为了保持一致,许多操作可以显式地抛出 BadRequest 异常。 # 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。 # 如果这个值被设置为 True ,你只会得到常规的回溯。 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', # 生成URL的时候如果没有可用的 URL 模式话将使用这个值 'JSON_AS_ASCII': True, # 默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False , # Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。 # 比如 jsonfiy 会自动地采用 utf-8 来编码它然后才进行传输。 'JSON_SORT_KEYS': True, #默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。 # 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。 # 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, }
以上这些Key,都可以被改写,当然他们也都是有默认值存在的,如果没有特殊情况,不要改写它的默认值
修改配置的方式大约是两种
1.直接对app.config进行修改
app.config["DEBUG"] = True # 等效app.debug=True app.run(debug=True)
2.使用类的方式导入
首先要有一个settings.py的文件
class FlaskSetting: DEBUG = True SECRET_KEY = "DragonFire"
然后我们在Flask的启动文件中就可以这么写
from flask import Flask from settings import FlaskSetting app = Flask(__name__) # type:Flask app.config.from_object("settings.FlaskSetting")
这叫做类导入配置
这是针对一个已经实例化的app进行的配置
那么在Flask实例化的时候,传递的参数是什么鬼呢?
其实可以理解为对Flask实例进行的初始配置,这里面的参数是非常好理解,注意关键字是非常非常非常好理解
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录 static_host = None, # 远程静态文件所用的Host地址,默认为空 static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用 # host_matching是否开启host主机位匹配,是要与static_host一起使用,如果配置了static_host, 则必须赋值为True # 这里要说明一下,@app.route("/",host="localhost:5000") 就必须要这样写 # host="localhost:5000" 如果主机头不是 localhost:5000 则无法通过当前的路由 host_matching = False, # 如果不是特别需要的话,慎用,否则所有的route 都需要host=""的参数 subdomain_matching = False, # 理论上来说是用来限制SERVER_NAME子域名的,但是目前还没有感觉出来区别在哪里 template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录 instance_path = None, # 指向另一个Flask实例的路径 instance_relative_config = False # 是否加载另一个实例的配置 root_path = None # 主模块所在的目录的绝对路径,默认项目目录
这里面,我们常用的参数有
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录 static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用 template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录
十、特殊装饰器
1. 特殊的装饰器之自定义方法
作用:可以在视图中定义函数,将函数名传给前端模板,模板中通过{ { 函数名()}} 直接应用
@app.template_global() # 全局可以直接使用 def a_and_b(a,b): return a+b @app.template_filter() # 偏函数, 类似于过滤器 def abc(a,b,c): return a+b+c
模板中应用{ {a_and_b(11,22) | abc(3,4)}} 可以将前面的值当成后面函数的第一个参数
2、请求前和请求后做些事,类似于django的中间件
@app.before_request ===> 类似django的 process_request
执行时间:在执行视图函数前
无返回值:继续下一个before_request
有返回值:从最后一个after_request开始倒序执行
@app.after_request ===> 类似process_response
执行时间:在视图执行之后
必须有参数
必须有返回值:且不能为str/int等不能调用的值
倒序执行一个个after_request [代码从上到下,反着执行]
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return "xxx" @app.before_request # 执行视图前执行的业务 def check_login(): print(1) @app.before_request # 执行视图前执行的业务 def check_login1(): print(2) return @app.after_request # 返回浏览器前执行的业务 def add_ms(response): print(3) return response @app.after_request def add_ms1(response): # 参数必须有 print(4) return response # 必须要有返回值,且不能为字符串 if __name__ == '__main__': app.run()
执行结果为:
1
2
4
3
还有一个@app.before_first_request:表示,当程序运行起来,第一个请求来的时候就只执行一次,下次再来就不会在执行了
其就是flash的本质,取一次值,就没了,相当于pop了,但在一个函数内取和拿值还在
3、Flash 闪存
session存在在服务端的一个字典里面,session保存起来,取一次里面还是有的,直到你删除之后才没有了
1、本质:flash是基于session创建的,flash支持往里边放值,只要你取一下就没有了,相当于pop了一下。不仅吧值取走,而且吧session里的东西去掉
2、闪现有什么用?
from flask import Flask,session,Session,flash,get_flashed_messages,redirect,render_template,request app = Flask(__name__) app.secret_key ='sdfsdfsdf' @app.route('/users') def users(): # 方式一 # msg = request.args.get('msg','') # 方式二 # msg = session.get('msg') # if msg: # del session['msg'] # 方式三 v = get_flashed_messages() print(v) msg = '' return render_template('users.html',msg=msg) @app.route('/useradd') def user_add(): # 在数据库中添加一条数据 # 假设添加成功,在跳转到列表页面时,显示添加成功 # 方式一 # return redirect('/users?msg=添加成功') # 方式二 # session['msg'] = '添加成功' # 方式三 flash('添加成功') return redirect('/users') if __name__ == '__main__': app.run(debug=True)
4、自定义错误代码如404,500等错误返回页面
@app.errorhandler(404) def my_error404(msg): msg = "页面被吃了" return msg @app.errorhandler(500) def my_error500(msg): msg = "自定义错误信息" return render_template('500.html', msg=msg)
1 2018年11月20日 2 上节回顾: 3 1.Flask 启动 4 from flask import Flask 5 app = Flask(__name__) 6 app.run() 7 8 2.Flask 路由 + 视图函数 9 @app.route("/index",methods=["GET","POST"]) 10 def index(): 11 pass 12 13 3.Response三剑客 + Flask小儿子: 14 HttpResponese return "" 15 render return render_template 模板默认目录 templates 16 redirect return redirect("/index") 17 18 小儿子: 19 send_file() # 打开文件并返回文件内容 20 jsonify() # 在返回的响应头中加入 Content-type:application/json 返回标准的json格式字符串 21 22 4.Request 23 from flask import request 24 25 获取参数(数据): 26 request.form # form表单中的数据 27 request.args # 获取URL地址中的参数数据 28 request.values # 获取 form + args 中的所有数据 29 request.json # Content-type:application/json 将数据存放在json中 30 request.data # 无法识别的Content-type b"" 31 32 获取请求信息: http://127.0.0.1:5000/index 33 request.method # 获取请求方式 8种 34 request.host #获取URL主机位 127.0.0.1:5000 35 request.url #获取请求的全部地址 http://127.0.0.1:5000/index 36 request.host_url # http://127.0.0.1:5000 37 request.path # 获取路由地址 38 39 5.Jinja2: 40 { {}} 引用 非逻辑 执行 41 {%%} 逻辑代码 if for 42 43 from flask import Markup 44 Markup 返回安全标签字符串 45 |safe 前端操作 返回安全标签字符串 46 47 {% macro func(a,b)%} 48 { {b}} 49 {% endmacro %} 50 { {func("http://","点击")}} 51 52 支持python 及 前端Object写法 53 54 6.Session: 55 from flask import session 56 app.secret_key = "12345678" 57 58 session["key"] = "value" 59 60 将Session序列化后,返回浏览器Cookie,再次请求的时候带上Session 61 62 上节作业: 63 64 65 今日内容: 66 1.Flask中的路由: 67 endpoint:反向URL from falsk import url_for 68 endpoint默认视图函数名 69 url_for("endpoint") 70 71 methods:允许访问该视图函数的请求方式 可迭代对象["GET","POST"] 72 73 defaults={ "nid":1} #默认参数 74 strict_slashes=True # 是否严格要求路由地址 "/" 75 redirect_to="/detail" # 请求层面的重定向 301 76 77 @app.route("/login/",methods=["GET","POST"],endpoint="login") 78 动态路由参数 79 def login(nid): 80 pass 81 82 2.Flask实例化配置: 83 template_folder="temps" 修改默认模板路径 84 static_folder="statics" 静态文件访问目录 85 static_url_path="/static" # 静态文件访问路径URL 86 默认 = "/" +static_folder 87 88 3.Flask配置: 89 secret_key 90 debug 91 testing 92 app.config.from_object #使用对象配置 93 94 4.蓝图 BluePrint 95 app01 = Blueprint("app01",__name__, 96 template_folder="temps", 97 static_folder="sta", 98 url_prefix="/app01") #url_prefix 蓝图前缀 99 app.register_blueprint(app01.app01) # 注册蓝图 100 101 5.特殊装饰器: 102 @app.template_global() # 全局函数 103 @app.template_filter() # 带筛选的全局函数 偏函数 104 @app.before_request # 在请求进入视图函数之前 105 @app.after_request # 在请求返回客户端之前 106 正常情况 :be1 - be2 - af2 - af1 107 异常情况 : be1 - af2 - af1 108 109 @app.errorheadler(404) # 更改报错页面 110 111 6.Flash 112 @app.before_first_request 113 def fr(): 114 115 flash(fr) # 在Flash存储信息 116 get_flashed_messages() # 获取Flash中的信息 并清空 117 118 [] - flash(fr) - [fr] - get_flashed_messages()=[fr].pop - fr() - [] 119 120 今日总结: 121 1.Flask 中的路由: 122 @app.route() 123 endpoint : 反向URL 默认是视图函数名 124 url_for(endpoint) 获取路由地址 125 methods : 允许进入视图函数的请求方式、 126 /login/ : 动态路由参数 def login(nid) 127 128 redirect_to : 请求进入视图函数之前重定向 301 129 strict_slashes True False: 是否严格要求路由地址 "/" 130 defaults = { "nid":1} : 默认参数 131 132 2.Flask实例化配置: 133 static_folder # 静态文件存放目录 134 static_url_path # 静态文件访问路径 "/static" 默认是"/"+static_folder 135 template_folder # 模板存放目录 136 137 3.Flask对象配置: 138 app.config.from_object(SettingClass) 139 140 4.蓝图 Blueprint 141 是一个不能被run的flask对象 142 from falsk import Blueprint 143 app01 = Blueprint("app01",__name__) 144 static_folder # 静态文件存放目录 145 static_url_path # 静态文件访问路径 "/static" 默认是"/"+static_folder 146 template_folder # 模板存放目录 147 148 app.register_blueprint(app01) 149 150 5.特殊装饰器: 151 @app.before_request # 在请求进入视图函数之前 152 @app.after_request # 响应返回客户端之前 153 正常情况:be1-be2-af2-af1 154 异常情况: be1-af2-af1 155 156 @app.errorheadler(404) def error404(arg) # 重定义错误返回信息 自定义错误页面 157 158 6.Flash 159 flash("123") # 在flash中存储数据 160 get_flashed_messages() # 将Flash中的所有数据获取并清空