Search code examples
flaskflask-admin

How to do an Ajax form field on Flask Admin


I'm building a Flask-Admin app that uses a REST API as its backend database, which I've implemented as my own BaseModelView. I've got it working with a custom model, and implemented all the functions to edit and save the model.

However I have one field, User, which needs to search another REST API endpoint for a User ID based on name/email, and as the list of users is expected to become quite large I want that field to be an AJAX lookup as I've seen in the SQLAlchemy example looking up a foreign key via Select2/Ajax.

As I need my own Ajax lookup, from following the docs and reading through the code, I'm struggling to find a working example of how to implement it myself and was wondering if anyone can direct me.

I've tried implementing an AjaxSelectField and using the form_ajax_refs property of BaseModelView to override the User field of the form (created in the scaffold_form method) without success.

Does anyone have an example of how I can put a custom Select2 Ajax lookup field, that looks up data from a REST API, on my model form so I can search for a User ID to assign to the model when I create/edit a model?


Solution

  • Figured it out finally, you have to add 2 things to your BaseModelView to do this:

    In your BaseModelView class - Add an AjaxSelectField to your form with a custom model form:

    def scaffold_form(self):
      class AccountForm(Form):
        owner =  AjaxSelectField(UserAjaxModelLoader('owner'),
                                         label='Owner', blank_text="Select User...")
      return AccountForm
    

    Then add a reference to your form_ajax_refs field:

    form_ajax_refs = {
        'owner': UserAjaxModelLoader('owner')
    }
    

    Finally the implementation of the UserAjaxModelLoader class which provides the AJAX endpoint and strings it all together:

    from flask_admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE
    
    class UserAjaxModelLoader(AjaxModelLoader):
    
        def __init__(self, name, **options):
            super(UserAjaxModelLoader, self).__init__(name, options)
    
        def format(self, model):
            if model:
                return (model.uid, model.email)
    
            return None
    
        def get_one(self, pk):
            return auth.get_user(pk)
    
        def get_list(self, query, offset=0, limit=DEFAULT_PAGE_SIZE):
    
            # Put your code to search REST API for users here
    
            return users