向应用程序工厂注册烧瓶管理视图的正确方法



我正在使用应用程序工厂向我的烧瓶应用程序添加视图,如下所示:

(这不是我的实际应用程序工厂,为了简洁起见,已缩短(

def create_app(config_name='default'):
    app = Flask(__name__, template_folder="templates", static_folder='static')
    admin_instance = Admin(app, name='Admin')
    admin_instance.add_view(EntityAdmin(Entity, db.session))

我的实体管理员类看起来像这样:

class EntityAdmin(ModelView):
    column_filters = [
        MyCustomFilter(column=None, name='Custom')
    ]

我的自定义过滤器如下所示:

class MyCustomFilter(BaseSQLAFilter):
    def get_options(self, view):
        entities = Entity.query.filter(Entity.active == True).all()
        return [(entity.id, entity.name) for entity in entities]

问题在于,似乎在实例化应用程序时调用了get_options函数,每次调用create_app函数时都会运行选择查询。

因此,如果我更新数据库架构并运行 flask db migrate 命令,则会收到错误,因为在运行选择查询时我添加的新列不存在。查询引发错误,因为我的数据库架构与实际数据库不同步。

我是否可以仅在发出实际的 HTTP 请求时注册我的视图?如何区分请求和命令?

此筛选器还有一个问题:它的选项是在应用程序实例化上创建的,因此,如果在应用程序运行期间更改了实体列表,它仍将返回相同的选项列表。

要解决这两个问题,您无需推迟视图注册。您需要过滤器在每次使用它时获取选项列表。

这个对"在 Python 中重置生成器对象"问题的 SO 回答描述了一种重用生成器的方法(在您的情况下 — 数据库查询(:

from flask import has_app_context
def get_entities():
    # has_app_context is used to prevent database access
    # when application is not ready yet
    if has_app_context():
        for entity in Entity.query.filter(Entity.active.is_(True)):
            yield entity.id, entity.name
class ReloadingIterator:
    def __init__(self, iterator_factory):
        self.iterator_factory = iterator_factory
    def __iter__(self):
        return self.iterator_factory()
class MyCustomFilter(BaseSQLAFilter):
    def get_options(self, view):
        # This will return a generator which is
        # reloaded every time it is used
        return ReloadingIterator(get_entities)

问题是在请求期间可以多次调用对Entity表的查询。所以我通常使用 Flask 全局变量缓存单个请求的结果:

def get_entities():
    if has_app_context():
        if not hasattr(g, 'entities'):
            query = Entity.query.filter(Entity.active.is_(True))
            g.entities = [(entity.id, entity.name) for entity in query]
        for entity_id, entity_name in g.entities:
            yield entity_id, entity_name

最新更新