【问题标题】:Flask Blueprint Initialization - Initializing some global variablesFlask Blueprint Initialization - 初始化一些全局变量
【发布时间】:2016-01-30 21:01:44
【问题描述】:

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

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

用其他方式来解释它:我有一个主应用程序,其中包含一些作为蓝图实现的子应用程序。主应用程序应包含一个导航栏,引用所有子应用程序(蓝图)。蓝图如何在主菜单导航变量中注册某些内容(例如在初始化时)?

(我没有找到从蓝图中访问类似“self.parent”或应用程序上下文的方法。蓝图没有类似构造函数的东西吗?)

【问题讨论】:

    标签: python flask blueprint


    【解决方案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 模板。请记住将此文件放在根项目的模板文件夹中,默认情况下,flask 会在该文件夹中搜索模板。

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

    从flask主应用程序对象,在本例中为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']
        ...
    

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

    【讨论】:

    • 感谢您的回答。没错,但这发生在蓝图中,由编写蓝图并将其添加到我的基础应用程序的人定义。但是我现在如何收集所有蓝图主路由和名称以在应用程序上下文中生成导航(例如,将其保存在应用程序上下文中以便稍后在调用 URL 时使用它)?此外,如果我想让蓝图作者能够以标准化的方式传递更多数据(例如,以哪种颜色显示他的作品的链接,或者其他什么...)。
    • 在主应用程序实例中,您有蓝图字典,您可以循环获取蓝图的每个实例并访问其属性。我会更新我的答案。
    • 谢谢,这解决了我的问题的核心。尽管如此,我真的很想将更多设置/数据从蓝图传递到应用程序上下文......以进一步自定义。假设一个蓝图想要告诉它的优先级(应该放置它的链接的位置),或者一种颜色,或者是否要禁止它被列出......
    • @j34,我更新了关于如何在应用程序和蓝图之间传递更多数据的问题。请检查它并让我知道该解决方案是否适合您。如果对您有效,请记住将答案标记为正确。
    • 哇,我想了很多,flask必须提供一些功能来做一些自定义蓝图初始化,我没有想到继承......非常感谢你的努力.
    【解决方案2】:

    在这里,我向您介绍一个我经常使用的可扩展应用程序模式。事实证明,工作正常。

    目录结构:

    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()
    

    plugins/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 平台证明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-12
      相关资源
      最近更新 更多