Flask快速开始

安装

Python版本

建议使用Python3。Flask支持Python3.4及以上、Python2.7和PyPy。

依赖

以下依赖包将会随Flask一同安装:

  • Werkzeug:执行WSGI,应用和服务间的Python标准接口
  • Jinja:一种服务器端用来渲染页面的模板语言
  • MarkupSafe:Jinja携带包,转义模板内容
  • ItsDangerous:数据签名工具,保证数据的完整性。用来保护Flask的session和cookie
  • Click:命令行工具,为flask提供命令行管理
可选依赖

以下依赖包不会随Flask一起安装,Flask会自动检测并使用这些包

  • Blinker:为信号提供支持
  • SimpleJSON:快速json解释器,兼容Python标准json模块,安装后会被优先使用
  • python-dotenv:运行flask应用时,为环境dotenv变量提供支持
  • Watchdog:提供更快更高效的开发服务器重启
虚拟环境

python3可以使用venv模块进行虚拟环境创建,而python2需要先安装virtualenv

创建虚拟环境

创建项目目录,并在该目录下创建venv目录:

mkdir myproject
cd myproject
python3 -m venv venv

windows:

py -3 -m venv venv

旧版本Python创建环境:

virtualenv venv

windows:

\Python27\Script\virtualenv.exe venv
启动环境

开发项目前,要开启对应的虚拟环境:

. venv/bin/activate

Windows:

venv\Script\activate

运行环境将切换到当前项目对应的环境中

安装Flask

在虚拟环境里执行:

pip install Flask

安装成功

快速开始

最小应用

最小的Flask应用,hello.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

不要把文件起名为flask.py,不然会覆盖引用进来的flask模块

hello.py运行起来:

$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/

Windows:

C:\path\to\app>set FLASK_APP=hello.py

还可以使用python -m flask命令:

$ export FLASK_APP=hello.py
$ python -m flask run
 * Running on http://127.0.0.1:5000/

127.0.0.1地址只能本机访问,改为0.0.0.0即可让网络内其他主机访问:

flask run --host=0.0.0.0
可能遇到的问题
import Name问题

FLASK_APP环境变量是导入的flask模块的名字,当FLASK_APP和所运行的flask项目文件名不一致时,将会导致import异常。通常导致该问题的原因是并未创建flask app对象

debug 模式

debug过程中希望项目能自动重启,并且显示错误信息,则需要开启debug模式:

$ export FLASK_ENV=development
$ flask run

Windows下将export改为set

这样配置后开启的功能:

  • 开启调试程序
  • 开启自动重启功能
  • 以debug模式运行Flask项目

还可以通过export参数FLASK_DEBUG=1的方式开启debug模式

路由

使用route()装饰器来绑定URL和视图函数:

@app.route('/')
def index():
    return 'Index Page'

@app.route('/hello')
def hello():
    return 'Hello, World'

不仅如此,还可以将url的部分内容设置为动态

可变规则

可以向URL添加变量,视图函数通过获取动态请求返回不同数据。<变量名>的方式传入普通变量,通过<转换类型:变量名>来指定变量转换类型:

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % subpath

可转换类型:

string(默认) 可接受任何不带斜线的参数
int接收正整数参数
float接收正浮点数参数
path类似 string ,但可以接收带斜线的参数
uuid接收UUID参数
唯一URL、URL跳转

如下两种方式对斜线的使用不一样。

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'

访问projects的URL时,如果没有在结尾带斜线,则falsk会为这次访问加上斜线

访问about的URL时,如果访问的时候带上了斜线,则访问不成功

这样做是为了保证URL唯一性

URL构造

使用url_for()函数来反向构造视图函数所对应的URL。url_for()接收视图函数名为第一个参数,后边可以传关键字参数,作为动态URL的参数。无法与URL参数对上的参数,则会转换为url请求参数跟在URL后边。

举例来说,可以通过使用test_request_context()方法来区分Flask所对应的URL:

from flask import Flask, url_for

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/login')
def login():
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return '{}\'s profile'.format(username)

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

/
/login
/login?next=/
/user/John%20Doe
HTTP请求方法

默认情况下Flask的视图函数值接收GET请求。可以通过route()methods参数来控制请求方法:

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return do_the_login()
    else:
        return show_the_login_form()

当允许接收的请求方法中包含GET方法时,Flask会自动支持HEAD方法

静态文件

在项目目录下创建static目录,则在本地开发时,可以通过访问static路径下相应文件名取到对应的静态文件:

url_for('static', filename='style.css')

则该css文件必须存储在static/style.css路径下

模板渲染

使用Python生成HTML内容是个苦力活,更不用说还要做HTML转义的工作。Flask支持jinja2模板引擎,可以帮我们自动生成HTML。

可以使用render_template()方法来渲染模板,我们提供模板名称以及想传入的参数即可:

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)

Flask会自动在template目录下寻找对应名称的模板文件,template目录与应用为同一级目录,或者属于应用的一级子目录:

/application.py
/templates
    /hello.html

或者

/application
    /__init__.py
    /templates
        /hello.html

jinja2模板语言示例:

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

模板中可以访问requestsession以及get_flashed_messages()函数等内容。

可以通过Markup类来做HTML转义:

>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello &lt;blink&gt;hacker&lt;/blink&gt;!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'&lt;blink&gt;hacker&lt;/blink&gt;')
>>> Markup('<em>Marked up</em> &raquo; HTML').striptags()
u'Marked up \xbb HTML'
使用request对象

Flask中,通过全局request对象来传递和存储客户端请求过程中的所有内容。那request对象是如何成为全局变量,而Flask又是如何保证线程安全的呢?这就不得不提上下文区域变量(context locals):

Context Locals

Flask中,一部分对象作为全局对象存在的。这些对象其实是邻近详细上下文对象的代理,

把上下文想象为处理线程,一个请求进来,而服务器产生一个新线程。当Flask在内部开始处理请求时,会发现当前线程已经是活跃的上下文,且绑定了当前应用和WSGI环境。这样一来,一个应用在不中断的情况下即可唤醒另一个应用。

上面一段讲了什么?除非要进行单元测试,一般情况下可以忽略这些过程。你会发现依赖于request对象的代码由于缺少request对象而停止了。解决办法是自己创建一个request对象并与上下文绑定。单元测试最简单的解决办法是使用test_request_context() 上下文管理器。使用with语句执行该方法,将绑定一个测试request对象,这样一来就可以与之交互。

from flask import request

with app.test_request_context('/hello', method='POST'):
    # now you can do something with the request until the
    # end of the with block, such as basic assertions:
    assert request.path == '/hello'
    assert request.method == 'POST'

另一种方法是将整个WSGI环境作为参数传入request_context()方法中:

from flask import request

with app.request_context(environ):
    assert request.method == 'POST'
Request对象

常用操作概述:

from flask import request

当前请求的方法可以通过method属性获得,请求的表单数据可通过form属性获得

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template('login.html', error=error)

form中不存在key值咋整?这种情况会抛出KeyError异常。可以通过标准KeyError捕捉异常,如果不进行异常处理,将会返回一个HTTP码为400的错误页面。因此大多数情况下不需要做处理。

通过arg属性来获取url中的参数:

searchword = request.args.get('key', '')

推荐使用get方法或捕捉异常的方式获取url参数,否则会显示400错误页,对用户来说是不友好的体验

文件上传

设置好 enctype="multipart/form-data属性后即可便捷地进行文件上传了

上传的文件存储在内存或文件系统的临时位置中。可以通过访问request对象的files属性来获取文件数据每个上传的文件都存在一个字典中,与普通python文件对象一样,不过有一个save()方法,用来将文件存储到服务器的文件系统中:

from flask import request

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/uploaded_file.txt')
    ...

可以通过访问filename 属性获得客户端上传文件的文件名,然而这些信息是不可信的,需要将文件名通过Werkzeug提供的secure_filename()方法来做一次安全性处理:

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/' + secure_filename(f.filename))
    ...
Cookies

通过request的cookies属性访问cookie,通过response的set_cookie方法设置cookie。cookies属性是一个包含客户端传来的所有cookie信息的字典。如果想使用sessions,不要直接使用cookie,而是使用Sessions 增加安全性

访问cookie:

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.

设置cookie:

@app.route('/')
def index():
    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp

可以看到,cookie是在response对象里进行设置的。由于一般的视图函数返回的都是字符串,Flask会将字符串转换为response对象。如果真的想设置cookie,可以通过make_response()函数修改。

跳转与错误

使用redirect() 函数跳转用户请求;使用abort()函数可以引发错误码,从而中止请求。

from flask import abort, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login')
def login():
    abort(401)
    this_is_never_executed()

默认错误页面对应不同的错误码。如果想改造错误页,可以使用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,它告诉Flask该请求需要返回404

Response对象

视图函数返回值会自动转换为response对象。Flask的转换规则如下:

  1. 如果视图返回了格式正确的response对象,则会直接返回,也就是不用再转换了;
  2. 如果视图返回的是字符串,则会将返回的数据和默认参数用来生成一个response对象;
  3. 如果返回一个元组,则元组元素包含了额外信息,这些元组一般以这种形式呈现;(response, status, headers)或(response, headers),元组里至少需要有一个元素。状态码的值会覆盖原有的状态码,而headers可以为一个列表或字典,作为额外的值添加进原来的header里
  4. 如果上述情况都没发生,Flask会将返回值替换为一个合法的WSGI应用,并将其转换为一个response对象

如果想改动response对象的内容,则需要在视图函数里调用make_response() 方法

假设你有一个这样的视图函数:

@app.errorhandler(404)
def not_found(error):
    return render_template('error.html'), 404

你只需要将返回值传到make_response()函数里,并且在得到response对象后进行修改:

@app.errorhandler(404)
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp
Sessions

想使用session,必须设定secret key,用来加密cookie信息。这样一来用户拿到cookie,在没有secret key的情况下是无法更改cookie中的数据的。

session的使用方法:

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()方法的作用是当你不使用模板引擎时,为你转义返回的内容

如何生成好的secret key:

秘钥需要越随机越好。操作系统提供生成随机数据。使用下面的命令可以快速生成一个secret_key

$ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值