Search code examples
pythonflaskflask-admin

Filtering the Drop Downs in Flask Admin Before it Gets to the User


I am implementing a interface for various companies to use the same Flask Admin instance to add and assign roles to their various users. However, I wish to make it so only the users which belong to the company viewing the data appear in the dropdowns that represent the one-to-many relationship between roles and users.

Is there something like get_query, but for the dropdown values?

Here is my current code for my view

class RoleView(ModelView):
    def get_query(self):
        return super(RoleView, self).get_query().filter(
            Role.company_id == current_user.company.id
        )

    def get_count_query(self):
        return super(RoleView, self).get_count_query().filter(
            Role.company_id == current_user.company.id
        )

and the model

class Role(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))

    users = db.relationship(
        'User',
        backref="role",
        lazy="dynamic"
    )
    company_id = db.Column(
        db.Integer,
        db.ForeignKey('company.id'),
        nullable=False
    )

Thanks


Solution

  • After digging through the source, I found this interesting line that led me to the correct answer https://github.com/flask-admin/flask-admin/blob/0f9f4b8695e3a7d00d9f3bae5fbf8f47f6a24e55/flask_admin/contrib/sqla/form.py#L81

    The QuerySelectMultipleField form field has a field called query_factory which accepts a function. So we can override this with form_args and a lambda:

    class RoleView(ModelView):
        column_exclude_list = ['company']
        form_excluded_columns = ['company']
    
        form_args = {
            'users': {
                'query_factory': lambda: User.query.filter_by(
                    company_id=current_user.company_id
                )
            }
        }
    
        def get_query(self):
            return super(RoleView, self).get_query().filter(
                Role.company_id == current_user.company.id
            )
    
        def get_count_query(self):
            return super(RoleView, self).get_count_query().filter(
                Role.company_id == current_user.company.id
            )