我是Flask的新手,我即将编写一个更大的应用程序。到目前为止,我将功能划分为蓝图。现在我希望能够在初始化期间从蓝图中设置一些全局变量(因此在请求上下文之外)。基本上,我想自动初始化某些蓝图的导航列表,因此每个蓝图都需要告诉我的基本应用程序它想要如何命名以及它的默认路由是什么。
我的目标是其他人可以通过将自定义蓝图放入我的应用程序的“插件”文件夹来扩展我的应用程序。在这种情况下,我的应用程序不知道他们的路由或名称。它需要在加载特定蓝图时自动学习...
以其他方式解释它:我有一个主应用程序包含一些实现为蓝图的子应用程序。主应用程序应该包含一个引用所有子应用程序(蓝图)的导航栏。蓝图如何在主菜单导航变量中注册(例如在初始化时)?
(我没有找到一种方法来访问类似“self.parent”或蓝图中的应用程序上下文。蓝图是否有类似构造函数的东西?)
答案 0 :(得分:1)
所以每个蓝图都需要告诉我的基础应用程序它想要的方式 被命名以及它的默认路线是什么。
创建蓝图时,您已在第一个参数中传递其名称:
simple_page = Blueprint('simple_page')
您也可以将 url_prefix 值传递给构造函数
simple_page = Blueprint('simple_page', url_prefix='/pages')
我有一个包含一些子应用程序的主应用程序 作为蓝图。主应用程序应该有一个导航栏 引用所有子应用程序(蓝图)
这是一个python模块中的示例,您应该将每个蓝图拆分到自己的模块中。
from flask import Flask, Blueprint, render_template
# ADMIN
admin = Blueprint('admin', __name__, url_prefix='/admin')
@admin.route('/')
def admin_index():
return 'Admin module'
@admin.route('/settings')
def settings():
return 'Admin Settings'
# USER
user = Blueprint('user', __name__, url_prefix='/user')
@user.route('/')
def user_index():
return 'User module'
@user.route('/profile')
def profile():
return 'User Profile'
app = Flask(__name__)
app.register_blueprint(admin)
app.register_blueprint(user)
@app.route('/')
def index():
return render_template('index.html', blueprints=app.blueprints)
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=7000)
Jinja2模板。请记住将此文件放在根项目的templates文件夹中,默认情况下,烧瓶会搜索模板。
<ul>
{% for bp_name, bp in blueprints.iteritems() %}
<li><a href="{{ bp.url_prefix }}">{{ bp.name }}</a></li>
{% endfor %}
</ul>
从烧瓶主应用程序对象(在本例中为 app ),您可以访问已注册的蓝图列表; app.blueprints ,这是一个python字典,其中包含您在构造函数中传递的蓝图的名称。因此,您将此对象传递给模板并在其上循环以在菜单中呈现名称和URL。
此外,如果我想让蓝图作者传递更多内容,该怎么办? 数据以标准化的方式(例如,显示链接的颜色 他的作品,或其他......)
由于这是一个特定于蓝图的数据,我认为一个好的解决方案是扩展Blueprint类并实现一个自定义方法,以标准化方式保存额外数据,然后从主应用程序对象访问。
custom.py
from flask import Blueprint
class MyBlueprint(Blueprint):
bp_data = {}
def set_data(data):
# here you can make extra task like ensuring if
# a minum group of value were provided for instance
bp_data = data
admin.py
from .custom import MyBlueprint
admin = MyBlueprint('admin', __name__, url_prefix='/admin')
admin.set_data({'color': '#a569bd', 'enabled': true})
# all the blueprint's routes
...
app.py
from admin import admin
app = Flask(__name__)
app.register_blueprint(admin)
@app.route('/')
def index():
for a, b in app.blueprints:
print b.bp_data['color']
print b.bp_data['enabled']
...
当然,我的自定义Blueprint类需要更多的工作,比如验证它传递的数据类型,或者如果没有所需的值就抛出错误,例如; title,require_auth 等。从这一点来说,您必须定义蓝图必须为主应用程序提供的最低要求数据才能正常工作。
答案 1 :(得分:0)
在这里,我向您展示了我经常使用的可扩展应用程序模式。事实证明工作正常。
目录结构:
YourApp
|- plugins (will contain all the user's plugins)
|- __init__.py (empty)
|-plugin1
|- __init__.py (empty)
|- loader.py
|- app.py
<强> app.py 强>
from flask import Flask
import os
def plugin_loader(app):
""" Function for discover new potencial plugins.
After checking the validity (it means, check if it implements
'register_as_plugin', load the user defined blueprint"""
plugins = [x for x in os.listdir('./plugins')
if os.path.isdir('./plugins/' + x)]
for plugin in plugins:
# TODO: Add checking for validation
module = __import__('plugins.' + str(plugin) + '.loader', fromlist=['register_as_plugin'])
app = module.register_as_plugin(app)
return app
# Creates the flask app
app = Flask(__name__)
# Load the plugins as blueprints
app = plugin_loader(app)
print(app.url_map)
@app.route('/')
def root():
return "Web root!"
app.run()
<强>插件/ plugin1 / loader.py 强>
from flask import Blueprint
plugin1 = Blueprint('plugin1', __name__)
@plugin1.route('/version')
def version():
return "Plugin 1"
def register_as_plugin(app):
app.register_blueprint(plugin1, url_prefix='/plugin1')
return app
所以期货插件应该在loader.py文件中的plugins /目录中实现 register_as_plugin 函数。
有关目录发现的更多信息,请阅读https://docs.python.org/2/library/os.path.html。 有关动态导入模块的更多信息,请阅读https://docs.python.org/2/library/functions.html#import。
使用Python 2.7.6,Flask 0.10.1和Unix平台进行了验证。