Мой __init__ в Flask-Admin ModelView не имеет контекста приложения - когда он обычно получается? - PullRequest
0 голосов
/ 22 мая 2018

У меня есть рабочий пример приложения Flask-Admin на GitHub , который запрашивает представление (само по себе основанное на MySQL information_schema.TABLES) для динамического обновления свойств ModelView column_labels и column_descriptions.Также есть небольшая модификация шаблона для добавления всплывающих подсказок в строку заголовка, содержащую комментарии к столбцу из базы данных.

Я приложил немало усилий, чтобы выяснить это, потому что было глупо повторно вводить описания столбцов в моем Pythonкод, когда они уже были введены в базу данных с использованием ключевого слова SQL COMMENT при создании таблицы.

В простом тестовом приложении все работает, как ожидалось;Я получаю параметры model и session, переданные методу ModelView __init__, и использую session, чтобы запросить у другой модели метки / комментарии столбцов, обновить self.column_labels и self.column_descriptions на экране, затем позвоните super().

Animated GIF showing column tooltips

Однако в более сложном приложении я получаю страшные RuntimeError: No application found. Either work inside a view function or push an application context при попыткезапросить другую модель в методе ModelView __init__.Единственное заметное различие, которое я хотел бы отметить между демонстрационным приложением и моим «настоящим» приложением, заключается в том, что я импортирую объект SQLAlchemy, созданный в другом файле .py, а затем вызываю его init_app() в моем app.py, чтобы подключить его кэкземпляр Flask.

Редактировать: точно в чем проблема ;SQLAlchemy экземпляры, созданные с использованием обычного способа, продемонстрированные в Flask-SQLAlchemy Quickstart , получают правильный экземпляр приложения Flask в своих __init__() s;когда я использую db.init_app(app), вместо этого появляется ошибка No application found.

Мой вопрос: с какого момента Flask-Admin ModelView начинает существовать в контексте приложения Flask? Чем отличаются обстоятельства для import db from somewhere.py; db.init_app(app) от db = SQLAlchemy(app)?Есть ли способ, которым я могу отследить процесс запуска приложения Flask и подключиться к этому точному моменту, чтобы я мог видеть, что здесь происходит?

Вот две основные части, которые участвуют (полный источник для каждый находится на GitHub, как отмечено выше):

Модель, предоставляющая столбец «метаданные», включая комментарии

# models.py
# [SQLALchemy imports and declaration of 'Base']
class ColumnProperty(Base):
    # this view is based on MySQL's 'information_schema.TABLES'
    __tablename__ = 'v_column_properties'

    parent_table = Column(String(64), primary_key=True)
    name = Column(String(64), primary_key=True)
    # [some fields elided]
    comment = Column(String(1024)) # type: str

и

ModelView, который запрашивает вышеуказанную модель при создании экземпляра

# views.py
from flask_admin.contrib.sqla import ModelView

class TestView(ModelView): 
    def __init__(self, model, session, **kwargs):
        from models import ColumnProperty as cp

        descriptions = {}
        q = session.query(cp).filter(cp.parent_table==model.__tablename__)

        for row in q.all():
            descriptions[row.name] = row.comment

        self.column_descriptions = descriptions 
        super(TestView, self).__init__(model, session, **kwargs)

1 Ответ

0 голосов
/ 22 мая 2018

Я бы переопределил render метод ModelView и установил бы там column_descriptions.Очевидно, что вы можете настроить какой-то механизм кэширования, чтобы уменьшить количество запросов к базе данных.

Что-то вроде (полностью не проверено) - обратите внимание на использование self.session в запросах:

# views.py
from flask_admin.contrib.sqla import ModelView

class TestView(ModelView):

    def render(self, template, **kwargs):
        from models import ColumnProperty as cp

        descriptions = {}
        q = self.session.query(cp).filter(cp.parent_table==model.__tablename__)

        for row in q.all():
            descriptions[row.name] = row.comment

        self.column_descriptions = descriptions

        super(TestView, self).render(template, **kwargs)
...