【发布时间】:2015-09-17 08:22:23
【问题描述】:
据我了解,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 Admin Model 视图中,该模型具有对 Product 模型的外键约束,我在表单创建视图中使用 form_ajax_refs,以允许选择动态加载的 Product项目。
form_ajax_refs = {"products": {"fields": (Product.title,)}}
这很好地显示了Product 模型的所有行。
不过,我目前的要求是仅使用 AJAX 模型加载器来显示具有特定 org_id 的产品,例如“Google”。
第 1 次尝试
覆盖ModelView 类的get_query 函数以加入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 类子类化并尝试覆盖它的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
然后我使用新的AjaxModelLoader 代替以前的form_ajax_refs 方法,如下所示:
form_ajax_refs = {
"products": ProductAjaxModelLoader(
"products", db.session, Product, fields=['title']
)
}
不幸的是,无论是用我的查询覆盖session 还是model 的值都不会从AJAX 加载器返回任何产品,而覆盖fields 仍然会返回所有产品;不仅仅是 org_id "Google" 的产品。
我希望不采取的措施
我希望能够在不必为每个组织创建新模型的情况下实现这一目标,因为这将被证明是不可扩展的并且设计不佳。
欢迎提出任何建议。谢谢。
【问题讨论】:
-
AjaxModelLoader 类如下所示:github.com/flask-admin/flask-admin/blob/master/flask_admin/… 您所要做的就是覆盖
get_list方法并以此为基础应用您的过滤器:github.com/flask-admin/flask-admin/blob/master/flask_admin/… -
好问题。如果flask-admin 结合了一种根据另一个字段的值来约束字段值的通用方法,那会很高兴。 +1
标签: python flask sqlalchemy flask-admin