1+1=10

记记笔记,放松一下...

Python flask入门笔记(一)

接前面Python的Web框架梳理WSGI入门笔记,了解一下Flask。

Flask是一款轻量级的用python实现的web微框架,它基于Werkzeug WSGI工具包和Jinja2模板引擎。

历史

Flask的作者是来自Pocoo的Armin Ronacher,Flask 首次发布于2010年4月1日,目前最新版本是3.0.0。

Flask 开发源于一个愚人节玩笑:Denied: the next generation python micro-web-framework

flask-histroy-denied-april-fools

图片来源:http://mitsuhiko.pocoo.org/flask-pycon-2011.pdf

2016年4月Pocoo团队解散,Flask开发移交给Pallets项目。

Hello world

一个最简单的Flask程序:

1
2
3
4
5
6
7
8
# hello.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'
  • 首先,导入Flask类,创建其实例 app,app是一个WSGI应用程序。注意其第一个参数,用于在文件系统中查找资源文件,对单个module,__name__没什么问题。
  • 使用装饰器route(),告诉Flask哪个URL会触发这个函数。

如何执行??

执行1

这是一个WSGI程序,所以,使用任何一个WSGI服务都可以启动这个程序。比如

使用 waitress

1
$ waitress-serve hello:app

使用 gunicorn

1
$ gunicorn -w 4 'hello:app'

等等...

另外,开篇我们提到了Flask依赖Werkzeug 这个 WSGI的python包,我们可以直接

1
2
import werkzeug.serving as serving
serving.run_simple('localhost', 8000, app)

也可以启用https:

1
2
import werkzeug.serving as serving
serving.run_simple('localhost', 8000, app, ssl_context=('111.cert', '111.key'))

执行2

当然,最简单的还是使用flask自带的命令行功能flask`python -m flask.`:

1
$ flask --app hello:app run 

其中

  • --host参数用于修改监听地址
  • --debug参数对于调试很有用
  • --app参数用于指定WSGI的入口

如果python脚本为 app.py 或 wsgi.py的话,且脚本内变量为app或application,可以省略--app直接执行:

1
$ flask run

如果脚本是其他名字,也可以同环境变量指定

1
2
$ export FLASK_APP=hello
$ flask run

执行 3

网上好多例子都是这么写的,可能这样更简单??!

使用Flask的run()函数,直接执行这个脚本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from flask import Flask

app = Flask(__name__)

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

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

当然,run也有很多参数可以配置,

1
run(*host=None*, *port=None*, *debug=None*, *load_dotenv=True*, ***options*)

因为它后台启动的是wekzeug的server。所以此处的options参数会传递给werkzeug.serving.run_simple()

在开发阶段,flask支持https也简单:

1
2
if __name__ == '__main__':
    app.run('localhost', 8000, ssl_context=('111.cert', '111.key'))

路由选择 Routing

wekzeug为flask提供了routing的底层机制:

  • Map
  • Rule
  • MapAdapter
1
2
3
4
5
from werkzeug.routing import Map, Rule
url_map = Map([
    Rule('/all/', defaults={'page': 1}, endpoint='all_entries'),
    Rule('/all/page/<int:page>', endpoint='all_entries')
])

Flask进一步进行封装

绑定

装饰器route()用于将函数绑定到一个URL地址(没有绑定的URL会报404错误):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from flask import Flask

app = Flask(__name__)

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

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

变量规则

可以通过<variable_name>将变量添加进URL,而后在函数中可以直接使用该变量。也可以为变量指定转换器,格式<converter:variable_name>:

1
2
3
4
5
6
7
@app.route('/user/<username>')
def show_user_profile(username):
    return f'User {username}'

@app.route('/post/<int:post_id>')
def show_post(post_id):
    return f'Post {post_id}'

转换器类型:

  • string:默认。接受斜杠外其他文字
  • int:正整数
  • float:正浮点数
  • path:类似string,但接受斜杠
  • any:
  • uuid:接收UUID字符串

唯一URL与重定向行为

路径是否以/结尾,有不同效果:

1
2
3
4
5
6
7
@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'
  • 前者接受/projects/projects/
  • 后者只接受/about,而/about/会触发404错误。对应唯一的URL

HTTP方法

route中可以指定methods。如果处理不同method时,用相同的数据,可以放到一个函数中:

1
2
3
4
5
6
7
8
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()
  • 注意:methods 默认是 GET(隐含能处理HEAD)。
  • route的其他参数:endpoint(默认用view function的名字)、view_funcdefaultssubdomain

如果要拆开的话,也可以用更简单的形式:

1
2
3
4
5
6
7
@app.get('/login')
def login_get():
    return show_the_login_form()

@app.post('/login')
def login_post():
    return do_the_login()

参考

  • https://github.com/pallets/flask
  • https://flask.palletsprojects.com
  • https://en.wikipedia.org/wiki/Flask_(web_framework)
  • http://mitsuhiko.pocoo.org/flask-pycon-2011.pdf
  • https://palletsprojects.com/p/jinja/
  • https://werkzeug.palletsprojects.com