фляга администрирования пользовательских QueryAjaxModelLoader
из того, что я понимаю, администратор Flask поддерживает использование AJAX для загрузки модели внешнего ключа. The Администратор Колбы-Документация По Модели охватывает основы под заголовком form_ajax_refs
. Мне удалось успешно использовать это во многих случаях, однако у меня возникают проблемы с уровнем кастомизации, что я надеюсь достичь. Позвольте мне уточнить.
у меня есть Product
модель Organisation
модель и таблица соединений для их связи, определенные как Итак:
class Product(Base):
__tablename__ = "products"
product_uuid = Column(UUID(as_uuid=True), primary_key=True)
title = Column(String, nullable=False)
description = Column(String, nullable=False)
last_seen = Column(DateTime(timezone=True), nullable=False, index=True)
price = Column(Numeric(precision=7, scale=2), nullable=False, index=True)
class Organisation(Base):
__tablename__ = "organisations"
org_id = Column(String, primary_key=True)
org_name = Column(String, nullable=False)
products = relationship(
Product,
secondary="organisation_products",
backref="organisations"
)
organisation_products_table = Table(
"organisation_products",
Base.metadata,
Column("org_id", String, ForeignKey("organisations.org_id"), nullable=False),
Column("product_uuid", UUID(as_uuid=True), ForeignKey("products.product_uuid"), nullable=False),
UniqueConstraint("org_id", "product_uuid"),
)
в представлении модели администратора колбы модели под названием CuratedList
это имеет ограничение внешнего ключа для Product
модель, я использую form_ajax_refs
в форме создать представление, чтобы разрешить выбор динамически загруженного Product
предметы.
form_ajax_refs = {"products": {"fields": (Product.title,)}}
это хорошо работает, чтобы показать мне все строки Product
модель.
мое текущее требование, однако, является используйте только загрузчик модели AJAX для отображения продуктов с определенным org_id, например "Погуглить."
Попытка № 1
переопределить о ModelView
класс присоединиться на organisation_products_table
и фильтра org_id
. Это выглядит примерно так:
def get_query(self):
return (
self.session.query(CuratedList)
.join(
curated_list_items_table,
curated_list_items_table.c.list_uuid == CuratedList.list_uuid
)
.join(
Product,
Product.product_uuid == curated_list_items_table.c.product_uuid
)
.join(
organisation_products_table,
organisation_products_table.c.product_uuid == Product.product_uuid
)
.filter(CuratedList.org_id == "Google")
.filter(organisation_products_table.c.org_id == "Google")
)
к сожалению, это не решит проблему, и возвращает такое же поведение, как:
def get_query(self):
return (
self.session.query(CuratedList)
.filter(CuratedList.org_id == self._org_id)
)
это не влияет на поведение form_ajax_refs
.
Попытка Номер 2
на Администратор Колбы-Документация По Модели упоминает другой способ использования form_ajax_refs
, который включает в себя использование QueryAjaxModelLoader
класса.
во второй попытке я подкласс QueryAjaxModelLoader
class и попробуйте переопределить значения it's model
, session
или fields
переменные. Что-то вроде этого:--33-->
class ProductAjaxModelLoader(QueryAjaxModelLoader):
def __init__(self, name, session, model, **options):
super(ProductAjaxModelLoader, self).__init__(name, session, model, **options)
fields = (
session.query(model.title)
.join(organisation_products_table)
.filter(organisation_products_table.c.org_id == "Google")
).all()
self.fields = fields
self.model = model
self.session = session
а потом вместо прежних form_ajax_refs
подход, я использую мой новый AjaxModelLoader
вот так:
form_ajax_refs = {
"products": ProductAjaxModelLoader(
"products", db.session, Product, fields=['title']
)
}
к сожалению, ли переопределение значений session
или model
С моим запросом возвращает no продукты из загрузчика AJAX и переопределение fields
по-прежнему возвращает все продукты; не только продукты org_id "Google".
к чему я надеюсь не прибегать
я хотел бы иметь возможность достичь этого без создание новой модели для каждой организации, поскольку это окажется не масштабируемым и плохим дизайном.
любые предложения приветствуются. Спасибо.
2 ответов
благодаря комментарию Joes к моему первоначальному вопросу, я сформулировал рабочее решение:
переопределить AjaxModelLoader
функции get_list
вот так:
def get_list(self, term, offset=0, limit=DEFAULT_PAGE_SIZE):
filters = list(
field.ilike(u'%%%s%%' % term) for field in self._cached_fields
)
filters.append(Organisation.org_id == "Google")
return (
db.session.query(Product)
.join(organisation_products_table)
.join(Organisation)
.filter(*filters)
.all()
)
после многих проб и ошибок, и благодаря сообщениям выше, я представляю общий способ передачи фильтров загрузчику модели Ajax.
вот общий класс, который включает фильтрацию по таблице внешнего ключа.
from flask_admin.contrib.sqla.ajax import QueryAjaxModelLoader, DEFAULT_PAGE_SIZE
class FilteredAjaxModelLoader(QueryAjaxModelLoader):
additional_filters = []
def get_list(self, term, offset=0, limit=DEFAULT_PAGE_SIZE):
filters = list(
field.ilike(u'%%%s%%' % term) for field in self._cached_fields
)
for f in self.additional_filters:
filters.append(f)
# filters.append(User.list_id == 2) # Now this is passed in the constructor
# filters.append(User.is_active == 'Y')
return (
db.session.query(self.model)
.filter(*filters)
.all()
)
def __init__(self, name, session, model, **options):
super(FilteredAjaxModelLoader, self).__init__(name, session, model, **options)
self.additional_filters = options.get('filters')
использование:
передать его в form_ajax_refs
Как вы бы QueryAjaxModelLoader
FilteredAjaxModelLoader('component', db.session, User, fields=['list_value'],
filters=[User.list_id == 2, User.is_active == 'Y'])
надеюсь, что это поможет.