2016-01-30 168 views
3

我是Flask的新手,我即将编写一个更大的应用程序。到目前为止,我已将功能划分为蓝图。现在我希望能够在初始化期间从蓝图内设置一些全局变量(因此在请求上下文之外)。基本上,我想自动初始化某些蓝图的导航列表,因此每个蓝图都需要告诉我的基本应用程序如何命名以及默认路线是什么。Flask蓝图初始化 - 初始化一些全局变量

我的目标是让其他人可以通过将他们的自定义蓝图放入我的应用程序的“插件”文件夹来扩展我的应用程序。在这种情况下,我的应用程序不知道他们的路线或名称。它需要自动学习它,同时加载特定的蓝图...

要解释它以某种其他方式:我有一个主要应用程序包含一些子应用程序实现为蓝图。主应用程序应该包含一个引用所有子应用程序(蓝图)的导航栏。蓝图如何在主菜单导航变量上注册一些东西(例如初始化时)?

(我没有找到一种方法来访问类似“self.parent”或从蓝图应用程序上下文,不要蓝图碰到这样一个构造函数?)

回答

0

所以每个蓝图的需求告诉我的基础应用程序如何命名 以及它的默认路由是什么。

当你创建一个蓝图,你已经在第一个参数传递它的名字:

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模板。请记住将此文件放置在您的根项目的模板文件夹中,默认情况下,该文件夹将在其中进行模板搜索。

<ul> 
    {% for bp_name, bp in blueprints.iteritems() %} 
    <li><a href="{{ bp.url_prefix }}">{{ bp.name }}</a></li> 
    {% endfor %} 
</ul> 

从烧瓶中主要应用对象,在这种情况下应用,您可以访问注册蓝图的列表; app.blueprints,这是一个python字典,其中包含您在构造函数中传递的蓝图的名称。所以你将这个对象传递给你模板并循环它以在菜单中呈现名称和URL。

而且,如果我想要的东西,使蓝图作者能够以标准化的方式传递更多 数据(例如,在色彩显示的链接 他的作品,或任何...)

由于这是一个蓝图的具体数据,我认为一个好的解决办法是延长蓝图类,并实现自定义的方法来保存在一个标准化的方式额外的数据,然后从主要应用对象访问即可。

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'] 
    ... 

当然,我的自定义蓝图类需要它更多的工作,比如验证什么如果没有所需的值,则传递的数据类型或抛出错误,如; title,require_auth等。从这一点出发,您必须定义蓝图必须提供给主应用程序才能正常工作所需的最小数据量。

+0

谢谢你的回答。确实如此,但是这种情况发生在蓝图内,并且由编写蓝图并将其添加到我的基本应用程序的人员来定义。但是,我现在应该如何收集所有蓝图主路线和名称,以便在应用程序上下文中生成导航(例如,将其保存在应用程序上下文中以便稍后在调用URL时使用它)? 此外,如果我想让蓝图作者以标准方式传递更多数据(例如用哪种颜色来显示链接到他的作品,或者其他什么),该怎么办。 –

+0

在主应用程序实例中,您有蓝图字典,您可以循环以获取蓝图的每个实例并访问其属性。我会更新我的答案。 – miso

+0

谢谢,这解决了我的问题的核心。不过,我真的很想将蓝图中的更多设置/数据传递到应用程序上下文...以进一步自定义。 假设一个蓝图需要告诉它的优先级(它应该放置链接的位置),还是一个颜色,或者是否要禁止它被列出来...... –

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 

所以期货插件应该实现register_as_plugin函数在loader.py文件中,在plugins /目录下的目录中。

有关目录发现的更多信息,您可以阅读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平台验证。