如何修改 Flask-Admin 列表中每个项目的可用操作
How to modify available actions for each item in a list in Flask-Admin
我想根据某些条件让一些行可编辑,而一些行只能查看,我该如何实现?
您可以通过覆盖 Flask-Admin list template 的 list_row_actions
块来完成此操作。此块将调用视图中定义的方法,将操作和行(即模型)作为视图中定义的每个行操作的参数。方法 returns True 或 False 取决于是否允许该操作。下面是一个简单的例子。
在templates/admin目录中创建list.html:
{% extends 'admin/model/list.html' %}
{% block list_row_actions scoped %}
{% for action in list_row_actions %}
{% if admin_view.allow_row_action(action, row) %}
{{ action.render_ctx(get_pk_value(row), row) }}
{% endif %}
{% endfor %}
{% endblock %}
注意 admin_view
是当前视图,我们创建了一个方法 allow_row_action
在视图中采用参数 action
和 row
(模型)。
在视图代码中定义一个mixin:
class RowActionListMixin(object):
list_template = 'admin/list.html'
def allow_row_action(self, action, model):
return True
任何实现此 mixin 的视图都将使用上面定义的重写列表模板。它还定义了 allow_row_action
方法 returns True.
现在按如下方式定义要控制行操作的任何视图:
class Student1View(RowActionListMixin, sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
column_filters = ('allow_edit', 'allow_delete')
def _can_edit(self, model):
# Put your logic here to allow edit per model
# return True to allow edit
return model.allow_edit
def _can_delete(self, model):
# Put your logic here to allow delete per model
# return True to allow delete
return model.allow_delete
def allow_row_action(self, action, model):
# # Deal with Edit Action
if isinstance(action, EditRowAction):
return self._can_edit(model)
# # Deal with Delete Action
if isinstance(action, DeleteRowAction):
return self._can_delete(model)
# # Deal with other actions etc
# otherwise whatever the inherited method returns
return super().allow_row_action()
注意被覆盖的 allow_row_method
。它检查操作是什么并将决策传递给适当的本地方法。
这是一个自包含的单个文件示例,您还需要上面定义的列表模板。 Student
模型有两个字段 allow_edit
和 allow_delete
以及 first_name
和 last_name
字段。 allow_edit
和 allow_delete
允许您动态切换是否可以编辑 Student
and/or 删除'。 Student1View
允许 editing/deleting 基于学生的 allow_edit
和 allow_delete
值。 Student2View
不会覆盖 allow_row_action
,因此允许执行行操作,因为 RowActionListMixin
class returns True
.[= 中定义的基本方法38=]
from faker import Faker
import click
from flask import Flask
from flask_admin.model.template import EditRowAction, DeleteRowAction
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib import sqla
db = SQLAlchemy()
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Text(length=255), nullable=False)
last_name = db.Column(db.Text(length=255), nullable=False)
allow_edit = db.Column(db.Boolean(), default=False, nullable=False)
allow_delete = db.Column(db.Boolean(), default=False, nullable=False)
def __str__(self):
return f"ID: {self.id}; First Name: {self.first_name}; Last Name: {self.last_name}"
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample.sqlite'
db.init_app(app)
@app.cli.command('create-database', short_help='Create student database')
@click.option('--count', default=100, help='Number of students (default 100)')
def create_database(count):
"""
Create database with "count" students
"""
db.drop_all()
db.create_all()
_faker = Faker()
for _ in range(0, count):
_student = Student(
first_name=_faker.first_name(),
last_name=_faker.last_name(),
allow_edit=_faker.boolean(),
allow_delete=_faker.boolean()
)
db.session.add(_student)
db.session.commit()
class RowActionListMixin(object):
list_template = 'admin/list.html'
def allow_row_action(self, action, model):
return True
class Student1View(RowActionListMixin, sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
column_filters = ('allow_edit', 'allow_delete')
def _can_edit(self, model):
# Put your logic here to allow edit per model
# return True to allow edit
return model.allow_edit
def _can_delete(self, model):
# Put your logic here to allow delete per model
# return True to allow delete
return model.allow_delete
def allow_row_action(self, action, model):
# # Deal with Edit Action
if isinstance(action, EditRowAction):
return self._can_edit(model)
# # Deal with Delete Action
if isinstance(action, DeleteRowAction):
return self._can_delete(model)
# # Deal with other actions etc
# otherwise whatever the inherited method returns
return super().allow_row_action()
class Student2View(RowActionListMixin, sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
column_filters = ('allow_edit', 'allow_delete')
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(Student1View(Student, db.session, name='Student 1', category='Students', endpoint='student-1'))
admin.add_view(Student2View(Student, db.session, name='Student 2', category='Students', endpoint='student-2'))
if __name__ == '__main__':
app.run()
我想根据某些条件让一些行可编辑,而一些行只能查看,我该如何实现?
您可以通过覆盖 Flask-Admin list template 的 list_row_actions
块来完成此操作。此块将调用视图中定义的方法,将操作和行(即模型)作为视图中定义的每个行操作的参数。方法 returns True 或 False 取决于是否允许该操作。下面是一个简单的例子。
在templates/admin目录中创建list.html:
{% extends 'admin/model/list.html' %}
{% block list_row_actions scoped %}
{% for action in list_row_actions %}
{% if admin_view.allow_row_action(action, row) %}
{{ action.render_ctx(get_pk_value(row), row) }}
{% endif %}
{% endfor %}
{% endblock %}
注意 admin_view
是当前视图,我们创建了一个方法 allow_row_action
在视图中采用参数 action
和 row
(模型)。
在视图代码中定义一个mixin:
class RowActionListMixin(object):
list_template = 'admin/list.html'
def allow_row_action(self, action, model):
return True
任何实现此 mixin 的视图都将使用上面定义的重写列表模板。它还定义了 allow_row_action
方法 returns True.
现在按如下方式定义要控制行操作的任何视图:
class Student1View(RowActionListMixin, sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
column_filters = ('allow_edit', 'allow_delete')
def _can_edit(self, model):
# Put your logic here to allow edit per model
# return True to allow edit
return model.allow_edit
def _can_delete(self, model):
# Put your logic here to allow delete per model
# return True to allow delete
return model.allow_delete
def allow_row_action(self, action, model):
# # Deal with Edit Action
if isinstance(action, EditRowAction):
return self._can_edit(model)
# # Deal with Delete Action
if isinstance(action, DeleteRowAction):
return self._can_delete(model)
# # Deal with other actions etc
# otherwise whatever the inherited method returns
return super().allow_row_action()
注意被覆盖的 allow_row_method
。它检查操作是什么并将决策传递给适当的本地方法。
这是一个自包含的单个文件示例,您还需要上面定义的列表模板。 Student
模型有两个字段 allow_edit
和 allow_delete
以及 first_name
和 last_name
字段。 allow_edit
和 allow_delete
允许您动态切换是否可以编辑 Student
and/or 删除'。 Student1View
允许 editing/deleting 基于学生的 allow_edit
和 allow_delete
值。 Student2View
不会覆盖 allow_row_action
,因此允许执行行操作,因为 RowActionListMixin
class returns True
.[= 中定义的基本方法38=]
from faker import Faker
import click
from flask import Flask
from flask_admin.model.template import EditRowAction, DeleteRowAction
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib import sqla
db = SQLAlchemy()
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Text(length=255), nullable=False)
last_name = db.Column(db.Text(length=255), nullable=False)
allow_edit = db.Column(db.Boolean(), default=False, nullable=False)
allow_delete = db.Column(db.Boolean(), default=False, nullable=False)
def __str__(self):
return f"ID: {self.id}; First Name: {self.first_name}; Last Name: {self.last_name}"
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample.sqlite'
db.init_app(app)
@app.cli.command('create-database', short_help='Create student database')
@click.option('--count', default=100, help='Number of students (default 100)')
def create_database(count):
"""
Create database with "count" students
"""
db.drop_all()
db.create_all()
_faker = Faker()
for _ in range(0, count):
_student = Student(
first_name=_faker.first_name(),
last_name=_faker.last_name(),
allow_edit=_faker.boolean(),
allow_delete=_faker.boolean()
)
db.session.add(_student)
db.session.commit()
class RowActionListMixin(object):
list_template = 'admin/list.html'
def allow_row_action(self, action, model):
return True
class Student1View(RowActionListMixin, sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
column_filters = ('allow_edit', 'allow_delete')
def _can_edit(self, model):
# Put your logic here to allow edit per model
# return True to allow edit
return model.allow_edit
def _can_delete(self, model):
# Put your logic here to allow delete per model
# return True to allow delete
return model.allow_delete
def allow_row_action(self, action, model):
# # Deal with Edit Action
if isinstance(action, EditRowAction):
return self._can_edit(model)
# # Deal with Delete Action
if isinstance(action, DeleteRowAction):
return self._can_delete(model)
# # Deal with other actions etc
# otherwise whatever the inherited method returns
return super().allow_row_action()
class Student2View(RowActionListMixin, sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
column_filters = ('allow_edit', 'allow_delete')
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(Student1View(Student, db.session, name='Student 1', category='Students', endpoint='student-1'))
admin.add_view(Student2View(Student, db.session, name='Student 2', category='Students', endpoint='student-2'))
if __name__ == '__main__':
app.run()