Flask:无法解析包中的端点位置
Flask: Trouble resolving endpoint locations in package
注意: 对最初的问题进行了大量编辑,包括最少的示例。原标题也有误导性。
我花了几天时间将一堆单独的应用程序和辅助模块重构为一个带有蓝图的大包。实际的 Flask 内容在包的 top-level 目录下几层,我已经在该目录中完成了所有测试。
打包并安装包后,url_for() 调用不再有效,因为应用程序规则中的端点现在包括蓝图视图函数的完整路径,而不仅仅是最后一点。
这是一个说明该问题的最小示例(下面附加的文件):
当应用程序 运行 来自其自己的目录时,规则如下所示:
$ python foo/test.py
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/bar/' (HEAD, OPTIONS, GET) -> bar.index>,
<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/other' (HEAD, OPTIONS, GET) -> other>]
...这就是模块基目录中 运行 时的样子:
$ python test.py
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/bar/' (HEAD, OPTIONS, GET) -> foo.bar.index>,
<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/other' (HEAD, OPTIONS, GET) -> other>]
注意“/”和“/other”(在应用程序中定义)的端点如何保持不变,而“/bar/”(在蓝图中定义)的端点获取包名称"foo" 前置。目前我所有的 url_for() 调用都使用 "short" 端点路径,我想保持这种方式,部分原因是我不想多次添加完整的包名,而且因为我不确定目录树是否会永远保持不变。
文件是这样的:
$ tree
.
├── foo
│ ├── app.py
│ ├── bar.py
│ ├── __init__.py
│ └── test.py
└── test.py
$ cat ./foo/app.py
import flask
from bar import blp
app = flask.Flask(__name__)
app.register_blueprint(blp, url_prefix='/bar')
@app.route('/')
def index():
pass
@app.route('/other')
def other():
pass
$ cat ./foo/bar.py
import flask
blp = flask.Blueprint(__name__, __name__)
@blp.route('/')
def index():
pass
$ cat ./foo/__init__.py
$ cat ./foo/test.py
from app import app
import pprint
rules = app.url_map.__dict__['_rules']
pprint.pprint(rules)
$ cat ./test.py
from foo.app import app
import pprint
rules = app.url_map.__dict__['_rules']
pprint.pprint(rules)
问题是由您分配给蓝图的名称引起的。蓝图中的每条规则都以名称为前缀。
因为您使用 __name__
作为蓝图的名称(蓝图构造函数的第一个参数)。在测试用例 foo/test.py
中,蓝图名称是 bar
。在测试用例 test.py
中,蓝图的名称是 foo.bar
.
解决方案是重写您的 bar.py
文件,如下所示:
import flask
blp = flask.Blueprint('bar', __name__)
@blp.route('/')
def index():
pass
注意: 对最初的问题进行了大量编辑,包括最少的示例。原标题也有误导性。
我花了几天时间将一堆单独的应用程序和辅助模块重构为一个带有蓝图的大包。实际的 Flask 内容在包的 top-level 目录下几层,我已经在该目录中完成了所有测试。
打包并安装包后,url_for() 调用不再有效,因为应用程序规则中的端点现在包括蓝图视图函数的完整路径,而不仅仅是最后一点。
这是一个说明该问题的最小示例(下面附加的文件):
当应用程序 运行 来自其自己的目录时,规则如下所示:
$ python foo/test.py
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/bar/' (HEAD, OPTIONS, GET) -> bar.index>,
<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/other' (HEAD, OPTIONS, GET) -> other>]
...这就是模块基目录中 运行 时的样子:
$ python test.py
[<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/bar/' (HEAD, OPTIONS, GET) -> foo.bar.index>,
<Rule '/' (HEAD, OPTIONS, GET) -> index>,
<Rule '/other' (HEAD, OPTIONS, GET) -> other>]
注意“/”和“/other”(在应用程序中定义)的端点如何保持不变,而“/bar/”(在蓝图中定义)的端点获取包名称"foo" 前置。目前我所有的 url_for() 调用都使用 "short" 端点路径,我想保持这种方式,部分原因是我不想多次添加完整的包名,而且因为我不确定目录树是否会永远保持不变。
文件是这样的:
$ tree
.
├── foo
│ ├── app.py
│ ├── bar.py
│ ├── __init__.py
│ └── test.py
└── test.py
$ cat ./foo/app.py
import flask
from bar import blp
app = flask.Flask(__name__)
app.register_blueprint(blp, url_prefix='/bar')
@app.route('/')
def index():
pass
@app.route('/other')
def other():
pass
$ cat ./foo/bar.py
import flask
blp = flask.Blueprint(__name__, __name__)
@blp.route('/')
def index():
pass
$ cat ./foo/__init__.py
$ cat ./foo/test.py
from app import app
import pprint
rules = app.url_map.__dict__['_rules']
pprint.pprint(rules)
$ cat ./test.py
from foo.app import app
import pprint
rules = app.url_map.__dict__['_rules']
pprint.pprint(rules)
问题是由您分配给蓝图的名称引起的。蓝图中的每条规则都以名称为前缀。
因为您使用 __name__
作为蓝图的名称(蓝图构造函数的第一个参数)。在测试用例 foo/test.py
中,蓝图名称是 bar
。在测试用例 test.py
中,蓝图的名称是 foo.bar
.
解决方案是重写您的 bar.py
文件,如下所示:
import flask
blp = flask.Blueprint('bar', __name__)
@blp.route('/')
def index():
pass