Search code examples
flaskflask-sqlalchemyflask-admin

Flask-admin editable select column row-based filter


I am using flask-admin to have easy edits on my DB model. It is about renting out ski to customers.

This is my rental view (the sql_alchemy DB model is accordingly):

class RentalView(ModelView):
    column_list = ("customer", "from_date", "to_date", "ski", "remarks")
    ...

customer and ski are relationship fields to the respective model. I want to only show these ski in the edit view that are not rented by others in this time period.

I have been searching everywhere how to dynamically set the choices of the edit form but it simply does not work fully.

I tried doing

def on_form_prefill(self, form, id):
    query = db.session.query... # do the query based on the rental "id"
    form.ski.query = query

and this correctly shows the filtered queries. However, when submitting the form, the .query attribute of the QuerySelectField ski is None again, hence leading to a query = self.query or self.query_factory() TypeError: 'NoneType' object is not callable error. No idea why the query is being reset?!

Does anybody know a different strategy of how to handle dynamic queries, based on the edited object's id?


Solution

  • Use this pattern, override the view's edit_form method, instance the default edit form (by calling the super() method then modify the form as you wish:

    class RentalView(ModelView):
    
        # setup edit forms so that Ski relationship is filtered
        def edit_form(self, obj):
    
            # obj is the rental instance being edited
            _edit_form = super(RentalView, self).edit_form(obj)
    
            # setup your dynamic query here based on obj.id
            # for example
    
            _edit_form.ski.query_factory = lambda: Ski.query.filter(Ski.rental_id == obj.id).all()
    
            return _edit_form