current_app 并在 Flask 中导入配置设置
current_app and importing config settings in Flask
最近,我开始使用 Flask 构建应用程序。它非常易于使用,但功能强大且使用起来很有趣。不幸的是,我在理解应用程序上下文的工作方式时遇到了问题。我知道 current_app
、app_context
并且 current_app
引用应该在请求中使用,但这可能是我问题的一部分。
我正在构建具有以下文件夹结构的应用程序:
app/
main/
__init__.py
error.py
forms.py
routes.py
static/
templates/
__init__.py
email.py
models.py
config.py
run.py
我正在 routes.py
中执行 from flask import current_app
以导入配置设置,它按预期工作。
但是当我在 forms.py
中导入 current_app 时,我可以做任何我想做的事,但我总是得到这个错误:
Traceback (most recent call last):
File "./run.py", line 6, in <module>
app = create_app('development')
File "/home/letmecode/Projects/python/flask/folder/app/__init__.py", line 34, in create_app
from main import main as main_blueprint
File "/home/letmecode/Projects/python/flask/folder/app/main/__init__.py", line 5, in <module>
from . import routes, errors, forms
File "/home/letmecode/Projects/python/flask/folder/app/main/routes.py", line 8, in <module>
from .forms import (ChangePasswordForm, ChangeEmailForm, CreateItemForm, RetrievePasswordForm, LoginForm,
File "/home/letmecode/Projects/python/flask/folder/app/main/forms.py", line 132, in <module>
class CreateItemForm(Form):
File "/home/letmecode/Projects/python/flask/folder/app/main/forms.py", line 133, in CreateItemForm
print current_app
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/werkzeug/local.py", line 362, in <lambda>
__str__ = lambda x: str(x._get_current_object())
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/werkzeug/local.py", line 302, in _get_current_object
return self.__local()
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/flask/globals.py", line 34, in _find_app
raise RuntimeError('working outside of application context')
RuntimeError: working outside of application context
forms.py
只是一个包含 flask-wtf 形式 类 和验证器函数的模块。
我的问题是,我想在其中引用应用程序上下文,以便获取在整个应用程序中使用的设置。
我在这里做错了什么?我想 forms.py
内部发生的事情不是请求的一部分,因此以某种方式失败了。但是我还应该如何引用应用上下文呢?
编辑:
#forms.py
from flask import current_app
#[...]
class CreateItemForm(Form):
title = TextField('Title', [
validators.Length(min=3, max=140),
validators.Regexp('^[a-zA-Z][a-zA-Z0-9 ]+$', 0, 'Item titles must start with a letter and consist of numbers and letters, only')
])
description = TextAreaField('Description', [
validators.Length(min=3, max=1000),
])
tags = TextField('Tags')
branch = SelectField(
'Branch',
choices=current_app.config['BRANCHES']
)
我发现我是个白痴。您不必为每个表单模型提供选择。您可以(并且应该)通过 view/route 函数提供它们,例如:
form.select_field.choices = [('value1', 'label1'), ('value2', 'label2')]
这并没有明确回答我的问题,但使它有些过时。但是,我不会接受我自己的答案作为解决方案(目前),因为我很好奇在这种情况下是否完全可以通过 app/current_app 导入配置选项,而不会变得笨拙。如果我的好奇心不能得到满足,我会接受我自己的答案。
我希望 wtforms/flask-wtf 文档少关注明显的问题,多关注不太明显的问题。
根本问题是 CreateItemForm
和所有属性都是在 forms
模块首次导入时创建的。这意味着每当 import .form
为 运行 时都会创建 branch
字段,因此 current_app
会被访问:
# app/main/routes.py
from .forms import ( ..., CreateItemForm, ...)
查看您的堆栈跟踪,这发生在您的 create_app
调用中 - 最有可能的是,您的 create_app
看起来像这样:
def create_app(config_name):
app = Flask('some-name-here')
app.config.from_SOMETHING(config_name)
# Register things here
from main import main as main_blueprint
app.register_blueprint(...)
return app
在 # Register things here
您可以简单地创建一个 app_context
并导入其中的所有内容:
# Register things here
# Creating an explicit application context to allow
# easy access to current_app.config, etc.
with app.app_context():
from main import main as main_blueprint
app.register_blueprint(...)
return app
最近,我开始使用 Flask 构建应用程序。它非常易于使用,但功能强大且使用起来很有趣。不幸的是,我在理解应用程序上下文的工作方式时遇到了问题。我知道 current_app
、app_context
并且 current_app
引用应该在请求中使用,但这可能是我问题的一部分。
我正在构建具有以下文件夹结构的应用程序:
app/
main/
__init__.py
error.py
forms.py
routes.py
static/
templates/
__init__.py
email.py
models.py
config.py
run.py
我正在 routes.py
中执行 from flask import current_app
以导入配置设置,它按预期工作。
但是当我在 forms.py
中导入 current_app 时,我可以做任何我想做的事,但我总是得到这个错误:
Traceback (most recent call last):
File "./run.py", line 6, in <module>
app = create_app('development')
File "/home/letmecode/Projects/python/flask/folder/app/__init__.py", line 34, in create_app
from main import main as main_blueprint
File "/home/letmecode/Projects/python/flask/folder/app/main/__init__.py", line 5, in <module>
from . import routes, errors, forms
File "/home/letmecode/Projects/python/flask/folder/app/main/routes.py", line 8, in <module>
from .forms import (ChangePasswordForm, ChangeEmailForm, CreateItemForm, RetrievePasswordForm, LoginForm,
File "/home/letmecode/Projects/python/flask/folder/app/main/forms.py", line 132, in <module>
class CreateItemForm(Form):
File "/home/letmecode/Projects/python/flask/folder/app/main/forms.py", line 133, in CreateItemForm
print current_app
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/werkzeug/local.py", line 362, in <lambda>
__str__ = lambda x: str(x._get_current_object())
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/werkzeug/local.py", line 302, in _get_current_object
return self.__local()
File "/home/letmecode/.virtualenvs/folder/local/lib/python2.7/site-packages/flask/globals.py", line 34, in _find_app
raise RuntimeError('working outside of application context')
RuntimeError: working outside of application context
forms.py
只是一个包含 flask-wtf 形式 类 和验证器函数的模块。
我的问题是,我想在其中引用应用程序上下文,以便获取在整个应用程序中使用的设置。
我在这里做错了什么?我想 forms.py
内部发生的事情不是请求的一部分,因此以某种方式失败了。但是我还应该如何引用应用上下文呢?
编辑:
#forms.py
from flask import current_app
#[...]
class CreateItemForm(Form):
title = TextField('Title', [
validators.Length(min=3, max=140),
validators.Regexp('^[a-zA-Z][a-zA-Z0-9 ]+$', 0, 'Item titles must start with a letter and consist of numbers and letters, only')
])
description = TextAreaField('Description', [
validators.Length(min=3, max=1000),
])
tags = TextField('Tags')
branch = SelectField(
'Branch',
choices=current_app.config['BRANCHES']
)
我发现我是个白痴。您不必为每个表单模型提供选择。您可以(并且应该)通过 view/route 函数提供它们,例如:
form.select_field.choices = [('value1', 'label1'), ('value2', 'label2')]
这并没有明确回答我的问题,但使它有些过时。但是,我不会接受我自己的答案作为解决方案(目前),因为我很好奇在这种情况下是否完全可以通过 app/current_app 导入配置选项,而不会变得笨拙。如果我的好奇心不能得到满足,我会接受我自己的答案。
我希望 wtforms/flask-wtf 文档少关注明显的问题,多关注不太明显的问题。
根本问题是 CreateItemForm
和所有属性都是在 forms
模块首次导入时创建的。这意味着每当 import .form
为 运行 时都会创建 branch
字段,因此 current_app
会被访问:
# app/main/routes.py
from .forms import ( ..., CreateItemForm, ...)
查看您的堆栈跟踪,这发生在您的 create_app
调用中 - 最有可能的是,您的 create_app
看起来像这样:
def create_app(config_name):
app = Flask('some-name-here')
app.config.from_SOMETHING(config_name)
# Register things here
from main import main as main_blueprint
app.register_blueprint(...)
return app
在 # Register things here
您可以简单地创建一个 app_context
并导入其中的所有内容:
# Register things here
# Creating an explicit application context to allow
# easy access to current_app.config, etc.
with app.app_context():
from main import main as main_blueprint
app.register_blueprint(...)
return app