Правильный способ регистрации просмотров флешки в админке с помощью фабрики приложений - PullRequest
0 голосов
/ 11 февраля 2019

Я использую фабрику приложений для добавления представлений в мое приложение для колб, например, так:

(это не моя фактическая фабрика приложений, и она была сокращена для краткости)

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

Мой класс EntityAdmin выглядит следующим образом:

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 вызывается, когдаприложение создается, выполняя запрос select каждый раз, когда вызывается функция create_app.

Поэтому, если я обновляю схему своей базы данных и запускаю команду flask db migrate, я получаю сообщение об ошибке, поскольку добавленный мной новый столбец не существует, когда выполняется запрос на выборку.Запрос вызывает ошибку, потому что моя схема базы данных не синхронизирована с фактической базой данных.

Могу ли я зарегистрировать свои представления только после выполнения фактического HTTP-запроса?Как я могу различить запрос и команду?

1 Ответ

0 голосов
/ 14 февраля 2019

У вас есть еще одна проблема с этим фильтром: его параметры создаются при создании экземпляра приложения, поэтому, если ваш список объектов был изменен во время работы приложения, он все равно будет возвращать тот же список параметров.

Исправитьобе проблемы вам не нужно откладывать просмотры регистрации.Вам нужен фильтр, чтобы получать список опций каждый раз, когда он используется.

Этот SO-ответ на вопрос «Сброс объекта генератора в Python» описывает способ повторного использования генератора (вваш случай - запрос к базе данных):

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 может быть вызван несколько раз во время запроса.Поэтому я обычно кеширую результат для одного запроса, используя Globals 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
...