视图类View
当flask程序收到一个客户端请求,需要一个 view_func
进行处理。前面我们一直老老实实定义处理函数,而后用装饰器route()
或者add_url_rule()
进行注册。
| from flask import Flask
app = Flask(__name__)
@app.route('/')
@app.route('/home')
def index():
return "Hello World!"
|
除了这个方式,flask还支持视图类View:
- 派生 Flask.views.View
- 定义类方法
dispatch_request
- 使用
add_url_url
注册绑定
| from flask import Flask, views
app = Flask(__name__)
class MyView(views.View):
def dispatch_request(self):
return 'Hello World!'
app.add_url_rule('/', view_func=MyView.as_view('myview'))
app.add_url_rule('/home', view_func=MyView.as_view('myview2'))
|
使用一个类,比一个函数有什么好处?
- 类支持继承,可以把共性的东西放到基类
- 比如flask中,MethodView是View的派生类
as_view
视图类不能使用装饰器,视图类不能直接注册,需要通过as_view()
生成一个view_func
而后进行注册。
前面例子中的两次as_view
生成两个视图函数。要生成一个,或许可以这样:
| app.add_url_rule('/', view_func=MyView.as_view('myview'))
app.add_url_rule('/home', endpoint='myview')
|
as_view()
的参数,必须传入一个name,如果有其他参数,会有View类的__init__()
处理。
methods
可以使用methods属性来设置该视图类要处理的请求:
| class MyView(View):
methods = ["GET", "POST"]
def dispatch_request(self):
if request.method == "POST":
return "Hello post"
return "Hello get"
app.add_url_rule('/my-view', view_func=MyView.as_view('my-view'))
|
这等同于在add_url_rule
中指定methods方法
MethodView
flask.views.MethodView是flask.views.View的派生类。对于定应REST API有用。
先把手册中的例子摆上,后面接触到REST后再回头看:
| class CounterAPI(MethodView):
def get(self):
return str(session.get("counter", 0))
def post(self):
session["counter"] = session.get("counter", 0) + 1
return redirect(url_for("counter"))
app.add_url_rule(
"/counter", view_func=CounterAPI.as_view("counter")
)
|
Blueprint
对于flask项目,蓝图(Blueprint)可以实现各个模块的划分。
不用蓝图
不使用蓝图时,flask项目大致长下面这样:
| myapp/
├── templates/
├── static/
└── app.py
|
但是如果有很多页面,这些页面有天然属于不同模块的话,应用文件app.py 可能长这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Hello World!'
# user
@app.route('/user/register')
def register():
return 'register'
@app.route('/user/login')
def login():
return 'login'
# admin
@app.route('/admin/users')
def listuser():
return 'users'
@app.route('/admin/deluser')
def deluser():
return 'deluser'
|
照这样下去,会很乱
使用Blueprint
蓝图方式,将代码按照功能模块进行划分
| myapp/
├── admin/
│ ├── __init__.py
│ └── views.py
├── app.py
└── user/
├── __init__.py
└── views.py
|
我们以admin为例,简单看看
创建蓝图
在admin目录下,我们需要一个__init__.py
文件
| from flask import Flask, Blueprint
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
from . import views
|
创建蓝图时,可以指定templates,static等资源的路径。
| class flask.Blueprint(name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, cli_group=<object object>)
|
视图
再创建一个views.py文件(注意使用上面创建的蓝图 装饰器):
1
2
3
4
5
6
7
8
9
10
11
12
13 | from admin import admin_bp
@admin_bp.route('/')
def home():
return 'Hello admin'
@admin_bp.route('/users')
def listuser():
return 'users'
@admin_bp.route('/deluser')
def deluser():
return 'deluser'
|
注册蓝图
在主程序 app.py 中,对蓝图进行注册:
| from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World!'
from admin import admin_bp
app.register_blueprint(admin_bp)
|
注册时,有其他参数可设置,比如 url_prefix='/admin'
。
有这三个文件,程序可以正常运行了...
杂项
创建蓝图时,指定静态文件夹(蓝图位于/admin,那么静态文件夹/admin/static):
| admin = Blueprint('admin', __name__, static_folder='static')
|
要生成静态文件的url(注意 蓝图名.static
),可以:
| url_for('admin.static', filename='style.css')
|
模板路径也可 指定:
| admin = Blueprint('admin', __name__, template_folder='templates')
|
蓝图组织方式
依据静态文件和模板文件的位置组织,蓝图有两种方式:
按蓝图分区
每个蓝图和它的资源在独立的目录下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | myapp/
├── app.py
├── static/
├── templates/
├── admin/
│ ├── __init__.py
│ ├── views.py
│ ├── static/
│ └── templates/
└── user/
├── __init__.py
├── views.py
├── static/
└── templates/
|
按功能
1
2
3
4
5
6
7
8
9
10
11
12 | myapp/
├── app.py
├── static/
│ ├── admin/
│ └── user/
├── templates/
│ ├── admin/
│ └── user/
└── view/
├── __init__.py
├── admin.py
└── user.py
|
官方示例
作为参考,Flask官方给出的完整结构示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | /home/user/Projects/flask-tutorial
├── flaskr/
│ ├── __init__.py
│ ├── db.py
│ ├── schema.sql
│ ├── auth.py
│ ├── blog.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── auth/
│ │ │ ├── login.html
│ │ │ └── register.html
│ │ └── blog/
│ │ ├── create.html
│ │ ├── index.html
│ │ └── update.html
│ └── static/
│ └── style.css
├── tests/
│ ├── conftest.py
│ ├── data.sql
│ ├── test_factory.py
│ ├── test_db.py
│ ├── test_auth.py
│ └── test_blog.py
├── .venv/
├── pyproject.toml
└── MANIFEST.in
|
参考
- https://github.com/pallets/flask
- https://flask.palletsprojects.com
- https://flask.palletsprojects.com/en/3.0.x/tutorial/views/
- https://flask.palletsprojects.com/en/3.0.x/views/
- https://flask.palletsprojects.com/en/3.0.x/blueprints/
- https://flask.palletsprojects.com/en/3.0.x/patterns/viewdecorators/
- https://blog.ashutoshkrris.in/how-to-use-blueprints-to-organize-your-flask-apps
- http://www.coolpython.net/flask_tutorial/basic/flask-blueprint.html