I use Flask-Admin and Flask-Security to implement admin panel for my Python application. Here are the models for User
and for Role
:
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
def __str__(self):
return self.name
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), unique=True, index=True)
password = db.Column(db.String(255))
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
def __str__(self):
return self.username
I created a sqla.ModelView
for User available only for users with roles "admin" and "superadmin", so such users can create new users using this view. How can I make only users with role "superadmin" can create users with roles "superadmin" and "admin"? In other words I want to specify which of the variants are available for users with different roles: https://i.sstatic.net/iKw13.jpg.
To do that you will have to customize a few things.
I would suggest the following:
add this method in your User model that checks if a user has a certain role:
def has_role(self, role):
# db is your database session.
query = db.query(Role).filter(Role.name == role).first()
if query:
if query.name in self.roles:
return True
return False
Now you have to customize the roles that are being displayed when a user tries to create a new user. To achieve that, you will need to change the definition of the roles field. To achieve that, you will need to override the flask-admin scaffold_form() method.
from flask_admin.contrib.sqla.fields import QuerySelectMultipleField
from flask_security import current_user
from flask_admin.form import Select2Widget
def scaffold_form(self):
form_class = super(YourUserAdminClass, self).scaffold_form()
role_filter = Role.name == Role.name if current_user.has_role('superadmin') else Role.name.notin_('superadmin', 'admin')
form_class.roles = QuerySelectMultipleField(
query_factory=lambda: self.session.query(Role).filter(role_filter),
allow_blank,
blank_text='Select Role',
widget=Select2Widget(multiple=False) # change this to True if you allow multiple roles
)
The code above will render the dropdown with the roles depending on the role that the current_user have (using the has_role()
method in the filter