作为微框架,即便只有一个文件也可以编写基于 Flask 的 Web 应用。然而对于许多现实世界中的应用,拥有数十个以上的视图(view)是非常正常的,这时候,Flask 建议使用多个 Python 模块来组织视图。例如:
/
yourapplication
/
yourapplication
/
__init__.py
/
views
__init__.py
admin.py
frontend.py
/
static
/
style.css
/
templates
layout.html
index.html
login.html
...
|
视图保存在包yourapplication.views中。这里只需要放置一个空白的__init__.py文件即可。我们来看看包中的admin.py文件。首先,我们使用 Python 模块名称创建一个 Flask 模块(flask.Module)对象,这个对象行为上非常类似 flask.Flask 对象,它们大多数方法都是一样的。下面是一个易于理解的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from
flask
import
Module
admin
=
Module(__name__)
@admin
.route(
'/'
)
def
index():
pass
@admin
.route(
'/login'
)
def
login():
pass
@admin
.route(
'/logout'
)
def
logout():
pass
|
对于frontend.py我们也可以做类似的处理,接下来,我们只需要确保在整个应用程序的__init__.py中注册这些模块即可:
1
2
3
4
5
6
7
|
from
flask
import
Flask
from
yourapplication.views.admin
import
admin
from
yourapplication.views.frontend
import
frontend
app
=
Flask(__name__)
app.register_module(admin, url_prefix
=
'/admin'
)
app.register_module(frontend)
|
通过将这些模块注册到应用中,应用程序的 URL 映射表就能够适用于这些模块中的配置了。请注意 admin 模块的注册参数 url_prefix:默认的当我们注册一个模块时,缺省的 endpoint 是“/”,要使用其它的前缀,必须通过 url_prefix 参数配置。
使用 Flask 模块和直接使用 Flask 对象有什么区别呢?最主要的区别在 URL 生成的问题上。例如,我们经常使用的 url_for() 函数,当直接与 Flask 对象一起工作时,它的第一个参数,也就是所谓的 endpoint,是视图函数的名称,而当结合 Flask 模块一起工作时,对于同一个模块中的视图函数,用法仍然一样,而对于别的模块中的函数,则需要使用模块名加上句点作为前缀。看看下面的例子可以帮助我们更 容易的理解这个问题。假设我们在 admin 模块中有一个需要重定向到 frontend 模块的函数,它看起来类似这样:
1
2
3
4
5
6
7
|
@admin
.route(
'/to_frontend'
)
def
to_frontend():
return
redirect(url_for(
'frontend.index'
))
@frontend
.route(
'/'
)
def
index():
return
"I'm the frontend index"
|
而如果我们只需要重定向到相同模块中的其它函数,那么我们既可以使用完成的 endpoint 路径,也可以只使用函数名:
1
2
3
4
5
6
7
|
@frontend
.route(
'/to_index'
)
def
to_index():
return
redirect(url_for(
'index'
))
@frontend
.route(
'/'
)
def
index():
return
"I'm the index"
|
更进一步,如果我们的 Module 对象是放在 Python 包中的,这样,我们有增加了额外的放置模板和静态文件的位置。假设我们的应用程序看起来像是这样的:
/
yourapplication
__init__.py
/
apps
__init__.py
/
frontend
__init__.py
views.py
/
static
style.css
/
templates
index.html
about.html
...
/
admin
__init__.py
views.py
/
static
style.css
/
templates
list_items.html
show_item.html
...
|
这些包中的静态目录将会被自动展开为 URL。假设这个admin模块是通过 /admin 前缀展现在 URL 中的,那么可以通过/admin/static/style.css 来访问其中的样式表文件。而该文件的 endpoint 则是 'admin.static'。
与 URL 规则可以省略前缀不同,我们总是需要使用完成的模块名称来引用模板,例如:render_template('admin/list_items.html') 等等。同样的,既然我们的视图函数已经从yourapplication.views.admin移动到yourapplication.apps.admin.views中了,我们需要在注册模块的时候明确的设置一个名称。这是由于再使用 __name__ 作为参数的话它这时候的值是 views 了:
1
2
|
# in yourapplication/apps/admin/views.py
admin
=
Module(__name__,
'admin'
)
|
同样的,引导程序也需要稍作调整:
1
2
3
4
5
6
7
8
|
# in yourapplication/__init__.py
from
flask
import
Flask
from
yourapplication.apps.admin.views
import
admin
from
yourapplication.apps.frontend.views
import
frontend
app
=
Flask(__name__)
app.register_module(admin, url_prefix
=
'/admin'
)
app.register_module(frontend)
|
值得注意的是,如果我们使用一个不合格的 endpoint,默认的 Flask 会将它当作是模块的静态文件目录,即便这个目录并不存在。这对于任何 endpoint 都有效,而不仅仅是名为 static 的目录,只不过通常我们使用 static 放置静态文件而非设置一个视图函数而已。如果需要使用整个应用程序的静态目录,可以在最开始加上一个句点:
1
2
3
4
5
|
# this refers to the application's static folder
url_for(
'.static'
, filename
=
'static.css'
)
# this refers to the current module's static folder
url_for(
'static'
, filename
=
'static.css'
)
|