我正在尝试使用蓝图在Flask中创建一个“模块化应用程序”。
但是,在创建模型时,我遇到了必须引用该应用程序才能获取dbFlask-SQLAlchemy提供的-object的问题。我希望能够在多个应用程序中使用一些蓝图(类似于Django应用程序的使用方式),所以这不是一个好的解决方案。*
可以进行切换,让蓝图创建db实例,然后由应用程序将其与其余的蓝图一起导入。但是随后,任何其他希望创建模型的蓝图都需要从该蓝图而不是应用程序中导入。 因此,我的问题是:
有没有一种方法可以让蓝图定义模型,而又不知道它们以后将使用的应用程序-并且有多个蓝图组合在一起?我的意思是必须从你的蓝图导入应用程序模块/软件包。
declarative_base()
也许最好的解决方案是像Ruby on Rails一样,将项目的模式定义在一个位置并进行分散。声明性SQLAlchemy类定义实际上更像是schema.rb,而不是Django的models.py。我想这也将使使用迁移(从Alembic或sqlalchemy-migrate)更容易。
我被要求提供一个示例,所以让我们做一些简单的事情:假设我有一个描述“ flatpages”的蓝图,这是存储在数据库中的简单,“静态”内容。它使用仅包含短名称(用于URL),标题和正文的表。这是simple_pages/__init__.py:
simple_pages/__init__.py
from flask import Blueprint, render_template from .models import Page flat_pages = Blueprint('flat_pages', __name__, template_folder='templates') @flat_pages.route('/<page>') def show(page): page_object = Page.query.filter_by(name=page).first() return render_template('pages/{}.html'.format(page), page=page_object)
然后,最好让这个蓝图定义自己的模型(位于中simple_page/models.py):
simple_page/models.py
# TODO Somehow get ahold of a `db` instance without referencing the app # I might get used in! class Page(db.Model): name = db.Column(db.String(255), primary_key=True) title = db.Column(db.String(255)) content = db.Column(db.String(255)) def __init__(self, name, title, content): self.name = name self.title = title self.content = content
我相信最真实的答案是模块化蓝图不应该直接与数据访问相关,而应该依赖于提供兼容实现的应用程序。
因此,给出你的示例蓝图。
from flask import current_app, Blueprint, render_template flat_pages = Blueprint('flat_pages', __name__, template_folder='templates') @flat_pages.record def record(state): db = state.app.config.get("flat_pages.db") if db is None: raise Exception("This blueprint expects you to provide " "database access through flat_pages.db") @flat_pages.route('/<page>') def show(page): db = current_app.config["flat_pages.db"] page_object = db.find_page_by_name(page) return render_template('pages/{}.html'.format(page), page=page_object)
因此,没有什么可以阻止你提供默认实现的。
def setup_default_flat_pages_db(db): class Page(db.Model): name = db.Column(db.String(255), primary_key=True) title = db.Column(db.String(255)) content = db.Column(db.String(255)) def __init__(self, name, title, content): self.name = name self.title = title self.content = content class FlatPagesDBO(object): def find_page_by_name(self, name): return Page.query.filter_by(name=name).first() return FlatPagesDBO()
并在你的配置中。
app.config["flat_pages.db"] = setup_default_flat_pages_db(db)
通过不依赖于db.Model的直接继承,可以使上述内容更简洁,而仅使用来自sqlalchemy的vanilla declarative_base,但这应该代表了它的要旨。