pallets-eco / flask-admin

Simple and extensible administrative interface framework for Flask
https://flask-admin.readthedocs.io
BSD 3-Clause "New" or "Revised" License
5.79k stars 1.57k forks source link

[sqla] How to make AJAX filter dynamic (based on current item) ? #2075

Open agordon opened 3 years ago

agordon commented 3 years ago

Hello,

First, thank you for all your work on flask-admin, it is extremely useful and powerful.

I'm using the sqla/ModelView to manage a (simple) table, which has a many-to-many relationship with another table. When editing/creating an item, I'm using form_ajax_refs to query items from the other table. It works great.

Now I'm looking for a way to dynamically filter the ajax query based on the values of the currently edited item.

To elaborate:

Here is a contrived example of the database using "children" and "toys", and a secondary many-to-many table connecting them (this is all standard SQLAlchemy):

class Child(db.Model):
    __tablename__ = 'children'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    preferred_color = db.Column(db.String)

    toys = db.relationship("Toy", secondary="toys_and_children" )

class Toy(db.Model):
    __tablename__ = 'toys'

    id = db.Column(db.Integer, primary_key=True)
    description = db.Column(db.String)
    color = db.Column(db.String)

    children = db.relationship("Child", secondary="toys_and_children" )

class ToysAndChildren(db.Model):
    __tablename__ = 'toys_and_children'

    id = db.Column(db.Integer, primary_key=True)

    child_id = db.Column(db.Integer, db.ForeignKey("children.id") )
    toy_id = db.Column(db.Integer, db.ForeignKey("toys.id"))

    child = db.relationship("Child")
    toy = db.relationship("Toy")

And below is a simple Flask-Admin/SQLA/ModelView class to list/edit/create the "children" table, using defaults for everything, and a custom ajax query to connect 'toys' records to 'children' records:


## A typical Flask-Admin model view for the "Child" class,
## with ajax query to autocomplete toys.

class ChildView(ModelView):
    form_ajax_refs = {
        'toys: {
            'fields': ('description', 'color'),
            'placeholder': 'Please select',
            'page_size': 10,
            'minimum_input_length': 1,
            'filters' : [  ]
        }
    }
[...]
admin.add_view(ChildView(Child, db.session,name="Children"))

This works great, but now I'd like to improve it:

When searching/auto-completing "toys" from the ChildView form, I would like to filter by the child's preferred_color field, and only show "toys" that match that color. I can't use the filters: [] part, because that is static and has no notion of what is the current Child object and its preferred_color value.

Is there any way to achieve this kind of dynamic filtering?

Thanks!

oleksandr-l5 commented 3 years ago

Hello. I think I have solution for your problem. If it is still relevant I can prepare some code

agordon commented 3 years ago

@oleksandr-l5 - any suggestions or ideas would be much appreciated. Thanks!

oleksandr-l5 commented 3 years ago

You can override form.js for adding all form field values into ajax_lookup request https://github.com/oleksandr-l5/fa_override/blob/master/static/fa_override/admin/js/form.js#L19 and get field values in custom ajax loader using request.args https://github.com/oleksandr-l5/fa_override/blob/master/views.py#L33