flask-admin: 如何只允许超级用户可以查看指定的 table 列?
flask-admin: how to allow only super users can view the specified table column?
我已经构建了一个名为 Project 的 table 应用程序,它存储在 sqlite 中,我只想允许 超级用户 创建、编辑数据时可以查看approve栏目。
Project 数据在 "class Project" 中检索,我添加了
if current_user.has_role('superuser')
在 "class ProjectView":
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_security import SQLAlchemyUserDatastore, current_user,UserMixin,
RoleMixin
from flask_admin.contrib import sqla
# Create Flask application
app = Flask(__name__)
app.config.from_pyfile('config.py')
db = SQLAlchemy(app)
# Define models
roles_users = db.Table(
'roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
)
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)
email = db.Column(db.String(255), unique=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.email
class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
team = db.Column(db.Unicode(64))
project_name = db.Column(db.Unicode(128))
approve = db.Column(db.Boolean())
# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
# Create customized model view class
class MyModelView(sqla.ModelView):
def is_accessible(self):
if not current_user.is_active or not current_user.is_authenticated:
return False
if current_user.has_role('superuser'):
return True
return False
def _handle_view(self, name, **kwargs):
if not self.is_accessible():
if current_user.is_authenticated:
# permission denied
abort(403)
else:
# login
return redirect(url_for('security.login', next=request.url))
class ProjectView(sqla.ModelView):
def is_accessible(self):
if not current_user.is_active:
return False
else:
return True
def _handle_view(self, name, **kwargs):
if not self.is_accessible():
if current_user.is_authenticated:
# permission denied
abort(403)
else:
if current_user.has_role('superuser'):
form_create_rules = [
rules.FieldSet(('team'), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name'),
'approve',
rules.Container('rule_demo.wrap', rules.Field('notes'))
]
else:
form_create_rules = [
rules.FieldSet(('team'), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name'),
#'approve',
rules.Container('rule_demo.wrap', rules.Field('notes'))
]
form_edit_rules = form_create_rules
create_template = 'rule_create.html'
edit_template = 'rule_edit.html'
@app.route('/')
def index():
return render_template('index.html')
# Create admin
admin = flask_admin.Admin(
app,
'Release Control System',
# log in success page
base_template='my_master.html',
template_mode='bootstrap3',
)
# Add model views
admin.add_view(MyModelView(Role, db.session))
admin.add_view(MyModelView(User, db.session))
admin.add_view(ProjectView(Project, db.session))
但它仍然不起作用,所有用户仍然可以查看 approve 列。好心提醒。提前致谢。
您可以使用 BaseModelView.column_list 属性来指定动态计算的可访问列列表,只需将其设为 属性。然而,ModelView
的不同 "field" 属性在应用程序启动时被缓存,因此您需要覆盖它们的缓存:
from flask import has_app_context
class ProjectView(sqla.ModelView):
@property
def _list_columns(self):
return self.get_list_columns()
@_list_columns.setter
def _list_columns(self, value):
pass
@property
def column_list(self):
if not has_app_context() or current_user.has_role('superuser'):
return ['team', 'project_name', 'approve']
else:
return ['team', 'project_name']
当 current_user
不可用时,在应用程序初始化期间使用 column_list
属性。使用 flask.has_app_context() 方法检查此状态并在启动时向应用程序传递完整的列列表。
如果您需要指定不同的列集进行编辑,您需要 form_rules
属性(您已经在问题中使用了它们):
from flask_admin.form import rules
class ProjectView(sqla.ModelView):
@property
def _form_edit_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_edit_rules.setter
def _form_edit_rules(self, value):
pass
@property
def _form_create_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_create_rules.setter
def _form_create_rules(self, value):
pass
@property
def form_rules(self):
form_rules = [
rules.FieldSet(('team',), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name')
]
if not has_app_context() or current_user.has_role('superuser'):
form_rules.append('approve')
form_rules.append(rules.Container('rule_demo.wrap', rules.Field('notes')))
return form_rules
此外,您不需要使用 _handle_view
将用户重定向到登录页面。为此,使用 BaseView.inaccessible_callback 方法:
def inaccessible_callback(self, name, **kwargs):
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('security.login', next=request.url))
class ProjectView(sqla.ModelView):
'''
def inaccessible_callback(self, name, **kwargs):
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('security.login', next=request.url))
'''
def is_accessible(self):
if not current_user.is_active or not current_user.is_authenticated:
return False
else:
return True
@property
def _list_columns(self):
return self.get_list_columns()
@_list_columns.setter
def _list_columns(self,value):
pass
@property
def column_list(self):
if not has_app_context() or current_user.has_role('superuser'):
return ['team', 'project_name', 'approve']
else:
return ['team', 'project_name']
form_edit_rules = column_list
create_template = 'rule_create.html'
edit_template = 'rule_edit.html'
class ProjectView(sqla.ModelView):
def inaccessible_callback(self, name, **kwargs):
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('security.login', next=request.url))
@property
def _form_edit_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_edit_rules.setter
def _form_edit_rules(self, value):
pass
@property
def _form_create_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_create_rules.setter
def _form_create_rules(self, value):
pass
@property
def form_rules(self):
form_rules = [
rules.FieldSet(('team'), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name')
]
if not has_app_context() or current_user.has_role('superuser'):
form_rules.append('approve')
form_rules.append(rules.Container('rule_demo.wrap',
rules.Field('notes')))
return form_rules
我想合并 FileAdmin(此处示例:https://github.com/flask-admin/flask-admin/tree/master/examples/file)。
也就是说只有在项目通过后(见图),用户才能将文件上传到系统自动指定的路径(比如:/Reviewer1/Reviewer2/file
)
我已经构建了一个名为 Project 的 table 应用程序,它存储在 sqlite 中,我只想允许 超级用户 创建、编辑数据时可以查看approve栏目。
Project 数据在 "class Project" 中检索,我添加了
if current_user.has_role('superuser')
在 "class ProjectView":
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_security import SQLAlchemyUserDatastore, current_user,UserMixin,
RoleMixin
from flask_admin.contrib import sqla
# Create Flask application
app = Flask(__name__)
app.config.from_pyfile('config.py')
db = SQLAlchemy(app)
# Define models
roles_users = db.Table(
'roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
)
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)
email = db.Column(db.String(255), unique=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.email
class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
team = db.Column(db.Unicode(64))
project_name = db.Column(db.Unicode(128))
approve = db.Column(db.Boolean())
# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
# Create customized model view class
class MyModelView(sqla.ModelView):
def is_accessible(self):
if not current_user.is_active or not current_user.is_authenticated:
return False
if current_user.has_role('superuser'):
return True
return False
def _handle_view(self, name, **kwargs):
if not self.is_accessible():
if current_user.is_authenticated:
# permission denied
abort(403)
else:
# login
return redirect(url_for('security.login', next=request.url))
class ProjectView(sqla.ModelView):
def is_accessible(self):
if not current_user.is_active:
return False
else:
return True
def _handle_view(self, name, **kwargs):
if not self.is_accessible():
if current_user.is_authenticated:
# permission denied
abort(403)
else:
if current_user.has_role('superuser'):
form_create_rules = [
rules.FieldSet(('team'), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name'),
'approve',
rules.Container('rule_demo.wrap', rules.Field('notes'))
]
else:
form_create_rules = [
rules.FieldSet(('team'), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name'),
#'approve',
rules.Container('rule_demo.wrap', rules.Field('notes'))
]
form_edit_rules = form_create_rules
create_template = 'rule_create.html'
edit_template = 'rule_edit.html'
@app.route('/')
def index():
return render_template('index.html')
# Create admin
admin = flask_admin.Admin(
app,
'Release Control System',
# log in success page
base_template='my_master.html',
template_mode='bootstrap3',
)
# Add model views
admin.add_view(MyModelView(Role, db.session))
admin.add_view(MyModelView(User, db.session))
admin.add_view(ProjectView(Project, db.session))
但它仍然不起作用,所有用户仍然可以查看 approve 列。好心提醒。提前致谢。
您可以使用 BaseModelView.column_list 属性来指定动态计算的可访问列列表,只需将其设为 属性。然而,ModelView
的不同 "field" 属性在应用程序启动时被缓存,因此您需要覆盖它们的缓存:
from flask import has_app_context
class ProjectView(sqla.ModelView):
@property
def _list_columns(self):
return self.get_list_columns()
@_list_columns.setter
def _list_columns(self, value):
pass
@property
def column_list(self):
if not has_app_context() or current_user.has_role('superuser'):
return ['team', 'project_name', 'approve']
else:
return ['team', 'project_name']
当 current_user
不可用时,在应用程序初始化期间使用 column_list
属性。使用 flask.has_app_context() 方法检查此状态并在启动时向应用程序传递完整的列列表。
如果您需要指定不同的列集进行编辑,您需要 form_rules
属性(您已经在问题中使用了它们):
from flask_admin.form import rules
class ProjectView(sqla.ModelView):
@property
def _form_edit_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_edit_rules.setter
def _form_edit_rules(self, value):
pass
@property
def _form_create_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_create_rules.setter
def _form_create_rules(self, value):
pass
@property
def form_rules(self):
form_rules = [
rules.FieldSet(('team',), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name')
]
if not has_app_context() or current_user.has_role('superuser'):
form_rules.append('approve')
form_rules.append(rules.Container('rule_demo.wrap', rules.Field('notes')))
return form_rules
此外,您不需要使用 _handle_view
将用户重定向到登录页面。为此,使用 BaseView.inaccessible_callback 方法:
def inaccessible_callback(self, name, **kwargs):
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('security.login', next=request.url))
class ProjectView(sqla.ModelView):
'''
def inaccessible_callback(self, name, **kwargs):
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('security.login', next=request.url))
'''
def is_accessible(self):
if not current_user.is_active or not current_user.is_authenticated:
return False
else:
return True
@property
def _list_columns(self):
return self.get_list_columns()
@_list_columns.setter
def _list_columns(self,value):
pass
@property
def column_list(self):
if not has_app_context() or current_user.has_role('superuser'):
return ['team', 'project_name', 'approve']
else:
return ['team', 'project_name']
form_edit_rules = column_list
create_template = 'rule_create.html'
edit_template = 'rule_edit.html'
class ProjectView(sqla.ModelView):
def inaccessible_callback(self, name, **kwargs):
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('security.login', next=request.url))
@property
def _form_edit_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_edit_rules.setter
def _form_edit_rules(self, value):
pass
@property
def _form_create_rules(self):
return rules.RuleSet(self, self.form_rules)
@_form_create_rules.setter
def _form_create_rules(self, value):
pass
@property
def form_rules(self):
form_rules = [
rules.FieldSet(('team'), 'Personal Info'),
rules.Header('Project Info'),
rules.Field('project_name')
]
if not has_app_context() or current_user.has_role('superuser'):
form_rules.append('approve')
form_rules.append(rules.Container('rule_demo.wrap',
rules.Field('notes')))
return form_rules
我想合并 FileAdmin(此处示例:https://github.com/flask-admin/flask-admin/tree/master/examples/file)。
也就是说只有在项目通过后(见图),用户才能将文件上传到系统自动指定的路径(比如:/Reviewer1/Reviewer2/file
)