快速上手
启动服务器
启动方法因平台的不同而不同
Linux
export FLASK_APP=hello.py # 配置FLASK_APP的环境变量
flask run # 运行flask
Windows CMD
set FLASK_APP=hello.py # 配置FLASK_APP的环境变量
python -m flask run
Windows PowerShell
$env:FLASK_APP = "hello.py"
python -m flask run
启动调试
启动调试只需要在启动服务器之前为FLASK_ENV
变量赋予development
即可
Linux:export FLASK_ENV=development
Windows CMD:set FLASK_ENV=development
Windows PowerShell:$env:FLASK_ENV = “development”
路由
route方法可以起到将不同的请求目标分给不同的函数的功能
from flask import Flask
app = Flask(__name__) # __name__是应用模块或者包的名称,单一模块下应当使用__name__
@app.route('/') # 当访问 http://example.com/ 时触发index()函数
def index():
return "index"
@app.route('/login') # 当访问 http://example.com/login 时触发login()函数
def login():
return "login"
变量规则
通过把URL的一部分作为参数传入函数中
@app.route('/<hostname>')
def host(hostname):
return "请求主机为:%s" % hostname
演示:
Request = http://example.com/flask
Response = 请求主机为:flask
唯一的URL/重定向行为
@app.route('/projects/')
# 请求是 /projects 或者是 /projects/ 都会触发,并且会将 /projects 308永久重定向到 /projects/
def projects():
return 'The project page'
@app.route('/about')
# 只有请求时 /about 时才会触发
def about():
return 'The about page'
URL构建
url_for()
函数可以构建指定函数的URL,它的第一个参数可以是函数名,也可以是任意关键字,位置变量将添加到URL中作为查询参数;它会将函数名或者关键字构建进URL中,是动态构建,而不是原本就写死的模板
from flask import url_for
@app.route("/")
def index():
return url_for("index") # /
@app.route("/host")
def host():
return url_for("host") # /host
@app.route("/login")
def login():
return url_for("login") # /login
HTTP 方法
Flask 缺省情况下只响应GET请求
我们可以使用methods参数来让它响应GET和POST请求
from flask import request
@app.route('/', methods=['POST', 'GET'])
def index():
if request.method == 'POST':
return "POST方法"
elif request.method == 'GET':
return "GET方法"
静态文件
使用url_for
方法可以构造出静态文件的URL
@app.route('/', methods=['GET', 'POST'])
def login():
return url_for('static', filename='style.css') # /static/style.css
注意url_for的第一个参数必须是 ‘static’ 否则会报错,静态文件也必须放在static目录下面
渲染模板
在Python中会常用jinja2
引擎来进行模板渲染
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
模板文件我们因该放在网站根目录 /templates 下面
render_template 函数的第一个参数就是模板文件名,name是传入到模板的参数
操作请求数据
通过method属性可以操作请求方法
@app.route('/', methods=['POST', 'GET'])
def index():
if request.method == 'POST':
return "POST方法"
elif request.method == 'GET':
return "GET方法"
请求对象
通过form属性可以处理表单数据(在POST或者PUT请求中传输的数据)
通过args.get方法可以处理GET请求的参数
@app.route('/', methods=['POST', 'GET'])
def index():
return "GET请求的参数:%s\nPOST请求的参数:%s" % (request.args.get('get', ''), request.form['post'])
文件上传
在上传文件的时候注意要在HTML表单中设置 enctype="multipart/form-data”
属性,否则浏览器将不会上传文件
from flask import request
from werkzeug.utils import secure_filename
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['the_file']
f.save('/var/www/uploads/' + f.filename)
...
f
是上传的文件的一个实例,类似于Python中打开文件
f.save
方法是将缓存文件保存到本地,请注意,f.filename
是可以被伪造的,请永远不要相信用户传入的任何参数,为了安全,我们可以使用 secure_filename
代替以保证安全
from werkzeug.utils import secure_filename
...
f.save('/var/www/uploads/' + secure_filename(f.filename))
Cookie
读取cookie:
要访问cookies可以使用 cookies 属性
from flask import request
@app.route('/')
def index():
username = request.cookies.get('username')
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
如果request.cookies.get()
写成 request.cookies
,即不适用get()方法则可以获取所有的cookie值
存储cookie:
使用set_cookie方法可以存储(设置)cookie
from flask import make_response
@app.route('/')
def index():
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')
return resp
重定向和错误
使用 redirect() 函数可以重定向。使用 abort() 可以 更早退出请求,并返回错误代码:
from flask import abort, redirect, url_for
@app.route('/')
def index():
return redirect(url_for('login'))
@app.route('/login')
def login():
abort(403)
使用 errorhandler()
装饰器可以定制出错页面
from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'), 404
注意 render_template()
后面的 404 ,这表示页面对就的出错 代码是 404 ,即页面不存在。缺省情况下
200 表示:一切正常。
补充
关于响应
视图函数的返回值会自动转换为一个响应对象。如果返回值是一个字符串,那么会被 转换为一个包含作为响应体的字符串、一个 200 OK
出错代码
和一个 text/html 类型的响应对象。如果返回值是一个字典,那么会调用 jsonify() 来产生一个响应。以下是转换的规则:
如果视图返回的是一个响应对象,那么就直接返回它。
如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的 响应对象。
如果返回的是一个字典,那么调用 jsonify
创建一个响应对象。
如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由 (response, status)
、 (response, headers)
或者 (response, status, headers)
组成。 status
的值会重载状态代码, headers
是一个由额外头部值组成的列表
或字典。
如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为 一个响应对象。
如果想要在视图内部掌控响应对象的结果,那么可以使用 make_response() 函数。
设想有如下视图:
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
可以使用 make_response() 包裹返回表达式,获得响应对象,并对该对象 进行修改,然后再返回:
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
JSON 格式的 API
JSON 格式的响应是常见的,用 Flask 写这样的 API 是很容易上手的。如果从视图 返回一个 dict
,那么它会被转换为一个
JSON 响应。
@app.route("/me")
def me_api():
user = get_current_user()
return {
"username": user.username,
"theme": user.theme,
"image": url_for("user_image", filename=user.image),
}
如果 dict
还不能满足需求,还需要创建其他类型的 JSON 格式响应,可以使用 jsonify() 函数。该函数会序列化任何支持的
JSON 数据类型。 也可以研究研究 Flask 社区扩展,以支持更复杂的应用。
@app.route("/users")
def users_api():
users = get_all_users()
return jsonify([user.to_json() for user in users])
会话
除了请求对象之外还有一种称为 session 的对象,允许你在不同请求 之间储存信息。这个对象相当于用密钥签名加密的 cookie ,即用户可以查看你的 cookie ,但是如果没有密钥就无法修改它。
使用会话之前你必须设置一个密钥。举例说明:
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method="post">
<p><input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
@app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
这里用到的 escape() 是用来转义的。如果不使用模板引擎就可以像上例 一样使用这个函数来转义。
如何生成一个好的密钥
生成随机数的关键在于一个好的随机种子,因此一个好的密钥应当有足够的随机性。 操作系统可以有多种方式基于密码随机生成器来生成随机数据。使用下面的命令 可以快捷的为 Flask.secret_key ( 或者 SECRET_KEY )生成值:
$ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'
基于 cookie 的会话的说明: Flask 会取出会话对象中的值,把值序列化后储存到 cookie 中。在打开 cookie 的情况下,如果需要查找某个值,但是这个值在请求中 没有持续储存的话,那么不会得到一个清晰的出错信息。请检查页面响应中的 cookie 的大小是否与网络浏览器所支持的大小一致。
除了缺省的客户端会话之外,还有许多 Flask 扩展支持服务端会话。
消息闪现
一个好的应用和用户接口都有良好的反馈,否则到后来用户就会讨厌这个应用。 Flask 通过闪现系统来提供了一个易用的反馈方式。闪现系统的基本工作原理是在请求结束时 记录一个消息,提供且只提供给下一个请求使用。通常通过一个布局模板来展现闪现的 消息。
flash() 用于闪现一个消息。在模板中,使用 get_flashed_messages() 来操作消息。完整的例子参见 消息闪现 。
日志
有时候可能会遇到数据出错需要纠正的情况。例如因为用户篡改了数据或客户端代码出错 而导致一个客户端代码向服务器发送了明显错误的 HTTP 请求。多数时候在类似情况下
返回 400 Bad Request
就没事了,但也有不会返回的时候,而代码还得继续运行 下去。
这时候就需要使用日志来记录这些不正常的东西了。自从 Flask 0.3 后就已经为你配置好 了一个日志工具。
以下是一些日志调用示例:
app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
logger 是一个标准的 Logger Logger 类, 更多信息详见官方的 logging 文档。
更多内容请参阅 应用错误处理 。
集成 WSGI 中间件
如果想要在应用中添加一个 WSGI 中间件,那么可以包装内部的 WSGI 应用。假设为了 解决 lighttpd 的错误,你要使用一个来自 Werkzeug 包的中间件,那么可以这样做:
from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)