flask admin自定义QueryAjaxModelLoader
据我所知,Flask Admin支持AJAX用于外键加载。 Flask Admin - Model Documentation涵盖了标题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
的模型的Flask管理模型视图中,该模型对Product
模型具有外键约束,我在创建视图中使用form_ajax_refs
来允许选择动态加载的Product
项目。
form_ajax_refs = {"products": {"fields": (Product.title,)}}
这很好地向我展示Product
模型的所有行。
然而,我目前的需求是仅使用AJAX模型加载器来显示具有特定org_id的产品,例如“Google”。
尝试1号
覆盖get_query
的功能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号
Flask Admin - Model Documentation提到了另一种使用form_ajax_refs
,它涉及使用QueryAjaxModelLoader
类。
在第二次尝试中,我QueryAjaxModelLoader
了QueryAjaxModelLoader
类,尝试覆盖它的model
, session
或fields
变量的值。 像这样的东西:
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
的值是否session
返回AJAX加载器中的任何产品,并且覆盖fields
仍会返回所有产品; 不只是org_id“Google”的产品。
我希望不去的地方
我希望能够在不需要为每个组织创建新模型的情况下实现这一目标,因为这将证明是不可扩展的且设计不好。
欢迎任何建议。 谢谢。
感谢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'])
希望有所帮助。
链接地址: http://www.djcxy.com/p/86243.html