问题
Following up on this question Flask-Admin Role Based Access - Modify access based on role I don't understand how to implement role-based views, especially regarding the form and column_lists.
Say I want MyModelView
to show different columns if the user is a regular user or a superuser.
Overriding is_accessible
in MyModelView
has no effect at all
from flask_security import Security, SQLAlchemyUserDatastore, current_user
class MyModelView(SafeModelView):
# ...
def is_accessible(self):
if current_user.has_role('superuser'):
self.column_list = superuser_colum_list
self.form_columns = superuser_form_columns
else:
self.column_list = user_colum_list
self.form_columns = user_form_columns
return super(MyModelView, self).is_accessible()
# Has same effect as
def is_accessible(self):
return super(MyModelView, self).is_accessible()
and defining conditional class attributes does not work either as current_user
is not defined (NoneType
error as per AttributeError on current_user.is_authenticated()). Doing the same in the ModelView's __init__
being equivalent, current_user
is still not defined
class MyModelView(SafeModelView):
#[stuff]
if current_user.has_role('superuser'):
column_list = superuser_colum_list
form_columns = superuser_form_columns
else:
column_list = user_colum_list
form_columns = user_form_columns
#[other stuff]
FYI, SafeModelView
can be any class inheriting from dgBaseView
in the previously mentioned question.
回答1:
I usually define view class attributes such as column_list
as properties. It allows you to add some dynamic logic to them:
from flask import has_app_context
from flask_security import current_user
class MyModelView(SafeModelView):
@property
def column_list(self):
if has_app_context() and current_user.has_role('superuser'):
return superuser_column_list
return user_column_list
@property
def _list_columns(self):
return self.get_list_columns()
@_list_columns.setter
def _list_columns(self, value):
pass
The problem with using this approach (and why your reassigning of column_list
values in is_accessible
function took no effect) is that many view attributes are cached on application launch and stored in private attributes. column_list
for example is cached in _list_columns
attribute so you need to redefine it as well. You can look how this caching works in flask_admin.model.base.BaseModelView._refresh_cache method.
Flask has_app_context
method is needed here because first column_list
read is happened on application launch when your current_user
variable has no meaningful value yet.
The same can be done with form_columns
attribute. The properties will look like this:
@property
def form_columns(self):
if has_app_context() and current_user.has_role('superuser'):
return superuser_form_columns
return user_form_columns
@property
def _create_form_class(self):
return self.get_create_form()
@_create_form_class.setter
def _create_form_class(self, value)
pass
@property
def _edit_form_class(self):
return self.get_edit_form()
@_edit_form_class.setter
def _edit_form_class(self, value):
pass
来源:https://stackoverflow.com/questions/47454315/flask-admin-different-forms-and-column-list-for-different-roles