FLask基础

快速上手

启动服务器

启动方法因平台的不同而不同

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)