安装

Flask主要有两个依赖:Werkzeug(负责路由、调试、WSGI)和Jinja2(负责模板)

先搭虚拟环境

虚拟环境是python解释器的一个私有副本(就像开小号),在这个环境中你可以随意造次,并且不会影响系统中的全局Python解释器,我是Win环境,需要有pip,然后在Powershell(cmd也可)里敲命令安装

Linux下: $ sudo agt-get install python-virtualenv

Win下(注意用管理员身份): pip install virtualenv

安装完毕后检查一下,显示版本号说明安装成功: virtualenv --version

下一步进入一个文件夹(最好是新建),在里面创建虚拟环境(参数是虚拟环境的名字,我的是Myenv):

PS S:\envA> virtualenv Myenv
Using base prefix 'c:\\program files (x86)\\python36-32'
New python executable in S:\envA\Myenv\Scripts\python.exe
Installing setuptools, pip, wheel...done.

成功后文件夹里多了一个Myenv文件夹,里面保存着虚拟环境,使用的时候需要激活,命令如下:

Linux下: $ source Myenv/bin/activate

Win下(注意目录位置): $ .\Myenv\Scripts\activete

这里我用Powshell出现了一个错误:

.\activate : 无法加载文件 S:\envA\Myenv\Scripts\activate.ps1,因为在此系统上禁止运行脚本。有关详细 信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。

查完发现是执行策略的问题,Powershell第一次运行时用的是Restricted(默认设置),该策略不允许任何脚本运行,用 get-executionpolicy 一看果然是,那就改成RemoteSigned,用 set-executionpolicy remotesigned 命令后就可以了,成功进入后命令行提示符的前面会加上环境名字:(Myenv) PS S:\envA>

Powershell脚本的4种执行权限:

  • Restricted——默认的设置, 不允许任何script运行
  • AllSigned——只能运行经过数字证书签名的script
  • RemoteSigned——运行本地的script不需要数字签名,但是运行从网络上下载的script就必须要有数字签名
  • Unrestricted——允许所有的script运行

如果用完了虚拟环境想退出来,就用deactivate命令

安装Flask

就一行:pip install flask, 在虚拟环境里输入即可(如果没进venv就安装在了全局里)

第一个程序

从程序实例开始

所有Flask程序必须创建一个程序实例(即Flask类的对象),服务器使用WSGI(简单说就是python程序与web服务器之间的一个接口)的协议,把接收到的请求都交给这个对象处理,创建如下:

from flask import Flask
app = Flask(__name__) # 只有一个参数__name__,用该参数决定程序的根目录,便于以后找资源

路由

为了知道程序实例对每个URL请求运行哪些代码,所以保存一个URL到python函数的映射关系,处理URL和函数之间的关系的程序称为路由

程序实例提供了app.route()装饰器,可以轻松将视图函数(即函数)装饰为路由,而且还可以动态传入参数,就像这样:

@app.route('/') # 这里将视图函数index注册为程序根地址
def index():
    return '<h1>Hi~ Im Index</h1>'

@app.route('/user/<name>') # 尖括号内的动态部分作为参数传入user中
def user(name):
    return '<h1>hello, %s!</h1>' % name

视图函数的返回值称为响应,是客户端接收到的内容,可以是HTML的简单字符串,也可以是复杂表单 动态部分默认使用字符串,也可以用类型定义,如:'路由/user/<int:id>'只匹配id为整数的URL

路由动态部分的类型定义:字符串,int,float,path(也是字符串但不把斜线视作分隔符)

运行服务器

程序实例用run方法启动,有一些启动参数如调试器(较常用,debug=True)和重载程序,随后服务器会进入轮询,等待并处理请求,Ctrl-C可以直接停止

完整代码

# demo.py 文件名
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>Hi~ Im Index</h1>'

@app.route('/user/<name>')
def user(name):
    return '<h1>hello, %s!</h1>' % name

if __name__ == '__main__':
    app.run(debug=True)

运行如下:

(Myenv) PS S:\envA> python .\demo.py
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 317-394-910
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

访问首页和欢迎页: 29

30

框架的一些设计理念

上下文

视图函数可以根据请求去访问一些对象,请求对象封装了客户端发送的HTTP请求

直白的方法是把请求对象作为参数传入视图函数进行访问,不过这样会使每个视图函数都添加一个参数,而且当需要同时访问其他对象时会更麻烦,难以维护,好在Flask用了上下文把一些对象变为全局可访问(在一个线程中),见下例:

from flask import request

@app.route('/')
def index():
    user_agent = request.headers.get('User-Agent')  # 获取请求上下文中的UA
    return '<p>browser: %s</p>' % user_agent

Flask的两种上下文

  • 程序上下文:current_app(当前的程序实例),g(处理请求时用作临时存储的对象,每次请求会重设)
  • 请求上下文:request(请求对象,封装了HTTP请求内容),session(用户会话,存储请求之间需要”记住”的值的字典)

上下文需要激活(或推送)后才能调用,请求处理完成后再将其删除,若没推送就使用上下文会导致错误:RuntimeError:working outside of application context, 调用app.app_context()可获得一个程序上下文

URL映射

URL映射是URL和视图函数之间的对应关系,当根据请求找视图函数时会在URL映射中寻找请求的URL

app.route装饰器和app.add_url_rule()都可以生成映射,检查映射用app.url_map

>>> app.url_map
Map([<Rule '/' (GET, OPTIONS, HEAD) -> index>,    # 首页君
 <Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>,    # 用于访问静态文件的路由
 <Rule '/user/<name>' (GET, OPTIONS, HEAD) -> user>])    # 之前注册的动态路由

其中OPTIONS、HEAD、GET都是请求方法,不同请求方法使用不同视图函数处理,前两个由Flask自动处理,所以在这个程序里相当于都用了GET方法

请求钩子

有时会有在处理请求之前或之后执行代码的情况,比如在请求最开始的数据库连接、认证等,Flask提供注册通用函数的功能(即请求钩子),当然也是用装饰器实现的

4种请求钩子:

  • before_first_request: 注册一个函数,在处理第一个请求之前运行
  • before_request:~,在每次请求之前运行
  • after_request:~,如果没有未处理的异常抛出,在每次请求之后运行
  • teardown_request:~,即使有未处理的异常抛出,也在每次请求之后运行

在请求钩子函数和视图函数之间用程序上下文变量g来实现数据的共享

响应

为了服从HTTP协议,视图函数的返回值里需要有状态码,即把数字代码作为第二个返回值,跟在相应文本之后,Flask默认为200;除了状态码还可以接收第三个参数:由header组成的字典

视图函数除了返回由1-3个值组成的元祖,还可以返回Response对象,make_response()函数可接收1-3个参数,并返回一个Response对象,下例返回了response对象:

from flask import make_response
@app.route('/')
def index():
    response = make_response('<h1>set cookie idnex</h1>')
    response.set_cookie('answer', '666')
    return response

特殊响应

重定向(302):指向一个新地址(由Location首部提供),除了用返回值和response对象,用redirect()更为方便

abort生成(404):用于处理错误,抛出异常并把控制权交给web服务器

Flask-Script扩展

虽然Flask的web服务器支持很多启动设置选项,但只能在脚本中作为参数传给程序实例的run()方法,极为不便,所以选用这个拓展,它为Flask程序添加一个命令行解析器,不仅自带常用选项,而且还支持自定义命令,安装只需一行码: pip install flask-script

初始化,把程序实例作为参数传给构造函数,初始化主类的实例后就可以使用:

from flask_script import Manager
...
manager = Manager(app)
...
if __name__ == '__main__':
    manager.run()

运行后可以看到参数,shell是在程序的上下文中启动python会话,runserver即启动web服务器,根据需要自行选择:

usage: demo.py [-?] {shell,runserver} ...

positional arguments:
  {shell,runserver}
    shell            Runs a Python shell inside Flask application context.
    runserver        Runs the Flask development server i.e. app.run()

optional arguments:
  -?, --help         show this help message and exit

runserver也有很多选项,具体在后面加个--help就能看到,要说一下--host参数,它管理web服务器监听来自客户端的连接,默认情况是监听localhost上的连接,如果要允许同网中的其他计算机连接服务器需要设为--host 0.0.0.0,这样一来就可以用外网IP来访问