From what I understand, Flask Admin supports using AJAX to load a foreign key model. Flask Admin - Model Documentation describes the basics under the heading form_ajax_refs . I managed to use this successfully in many cases, but I am having problems with the level of customization that I hope to achieve. Let me clarify.
I have a Product model, an Organisation model, and a connection table for matching them, defined like this:
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"), )
In the model view of the flags panel of the model named CuratedList , which has a foreign key constraint for the Product model, I use form_ajax_refs in the create view form to allow the selection of dynamically loaded Product elements.
form_ajax_refs = {"products": {"fields": (Product.title,)}}
This works well to show me ALL rows of the Product model.
However, my current requirement is to use the AJAX model loader to display products with a specific org_id, such as Google.
Attempt No. 1
Cancel the get_query function of the ModelView class to join the organisation_products_table and filter by org_id . It looks something like this:
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") )
Unfortunately, this does not solve the problem and returns the same behavior as:
def get_query(self): return ( self.session.query(CuratedList) .filter(CuratedList.org_id == self._org_id) )
This does not affect the behavior of form_ajax_refs .
Attempt number 2
Flask Admin - Model Documentation mentions another way to use form_ajax_refs , which involves using the QueryAjaxModelLoader class.
In my second attempt, I subclass the QueryAjaxModelLoader class and try to override the values ββof the model , session or fields variables. Something like that:
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
And then, instead of the previous form_ajax_refs approach form_ajax_refs I use the new AjaxModelLoader like this:
form_ajax_refs = { "products": ProductAjaxModelLoader( "products", db.session, Product, fields=['title'] ) }
Unfortunately, overriding session or model values ββwith my request does not return any products from the AJAX loader, and overriding fields will still return all products; not just org_id google products.
What I hope not to resort to
I would like to be able to achieve this without , in order to create a new model for each organization, as this will turn out to be scalable and poor design.
Any suggestions are welcome. Thanks.