从 Flask-Admin 迁移
starlette-admin 最初就是将 Flask-Admin 的理念移植到 ASGI 生态的产物,因此迁移路径非常直接。你仍然继承 ModelView,用类属性进行配置,并在 Admin 实例上注册。大部分工作只是重命名属性,以及从 Flask 的隐式请求上下文转向 Starlette 的显式 request 对象。
本指南将逐一对照属性,把 Flask-Admin API 映射到 starlette-admin 中的对应实现。
心智模型
| Flask-Admin 概念 | starlette-admin 对应实现 |
|---|---|
Admin(app, name="...") |
Admin(engine, title="..."),然后调用 admin.mount_to(app) |
ModelView(Model, db.session) |
ModelView(Model);Admin 实例持有引擎和数据库会话 |
flask_admin.contrib.sqla |
starlette_admin.contrib.sqla |
flask_admin.contrib.mongoengine |
starlette_admin.contrib.mongoengine |
| peewee / pymongo 后端 | Beanie、Tortoise ORM、SQLModel,或自定义后端 |
BaseView + @expose |
CustomView |
AdminIndexView |
Admin(index_view=...)、DefaultIndexView |
Flask 请求上下文(flask.request) |
每个钩子上显式的 request: Request 参数 |
| 同步方法 | async 方法;在接受可调用对象之处仍可使用同步 |
初始设置
这里没有 template_mode 开关。UI 使用 Tabler(Bootstrap 5),并包含深色模式。要改变外观,可以编写自定义的 BaseTheme 或覆盖模板。
列表页属性
| Flask-Admin | starlette-admin | 说明 |
|---|---|---|
column_list |
fields |
同时驱动详情页和表单页。使用 exclude_fields_from_* 属性可实现各页面的差异化。 |
column_exclude_list |
exclude_fields_from_list |
|
column_labels |
label= |
例如,StringField("title", label="Headline")。 |
column_descriptions |
help_text= |
应用于字段定义。 |
column_formatters |
字段上的 formatter= |
例如,StringField("title", formatter={RequestAction.LIST: lambda request, value: value[:40]})。 |
column_formatters_detail / 导出格式化器 |
同一个 formatter= 字典,以 RequestAction 为键 |
一个映射即可覆盖列表、详情和导出的格式化。没有对应条目的动作将保留原始值。 |
column_type_formatters |
每字段的 formatter=,或自定义字段子类 |
没有按类型划分的注册表。将格式化器附加到各个字段,或者继承字段类以便复用。 |
column_list 中的模型属性或可调用对象 |
ComputedField,或任意字段上的 getter= |
无需子类即可添加虚拟列,或改变已有字段的取值来源。 |
| 自定义 WTForms 字段(值转换) | 字段上的 parser= |
按 RequestAction 替换字段的默认表单解析或导入解析逻辑。 |
column_searchable_list |
searchable_fields |
|
column_filters |
searchable_fields 结合每字段的 filters= |
用一个支持嵌套 AND/OR 分组的可视化构建器取代扁平的过滤器列表。 |
column_sortable_list |
sortable_fields |
|
column_default_sort |
fields_default_sort |
例如,[("created_at", True)] 表示按降序排序。 |
column_editable_list |
inline_editable_fields |
用户选中单元格后即可就地编辑。 |
page_size |
page_size |
|
can_set_page_size |
page_size_options |
默认为 [10, 25, 50, 100]。用户从这些选项中选择。 |
column_display_pk |
在 fields 中包含主键 |
|
column_details_list |
fields 减去 exclude_fields_from_detail |
详情页是内置的,无需 can_view_details 选择性开启。 |
表单属性
| Flask-Admin | starlette-admin | 说明 |
|---|---|---|
form_columns |
fields 减去 exclude_fields_from_create 和 exclude_fields_from_edit |
|
form_excluded_columns |
exclude_fields_from_create、exclude_fields_from_edit |
为每个表单提供独立的可见性控制。 |
form_overrides |
fields 中的显式字段实例 |
例如,fields = ["id", TextAreaField("bio")] |
form_args |
字段上的构造参数 | 例如,StringField("title", required=True, help_text="...") |
form_choices |
EnumField |
例如,EnumField("status", choices=[("draft", "Draft"), ("live", "Live")]) |
form_extra_fields |
fields 中的额外条目 |
支持任何不基于数据库列的字段,例如 ComputedField。 |
form_widget_args |
字段属性 | 直接在字段上设置 read_only、disabled 或 placeholder。 |
form_rules |
form_layout |
用字段集、选项卡和响应式网格取代扁平规则。 |
create_modal / edit_modal |
不支持 | 创建和编辑视图渲染为完整页面。 |
on_form_prefill |
before_edit 钩子 |
导出与导入
CSV 和 JSON 导出默认开启。行数上限自动生效,电子表格公式转义则是导出器的可选设置。导入是 Flask-Admin 所不具备的功能:它包含一个预览步骤,可逐行校验,并能通过主键选择性地更新现有记录。参见导出与导入。
动作
from starlette_admin import ActionSelection, action, flash
class PostView(ModelView):
actions = ["publish", "delete"]
@action(
name="publish",
text="Publish",
confirmation="Publish selected posts?",
)
async def publish(self, request: Request, selection: ActionSelection) -> None:
for post in await selection.rows():
post.published = True
flash(request, "Posts published")
处理函数接收的是 ActionSelection 对象,而不是原始 ID。它会惰性解析行数据,暴露当前生效的过滤器,并且在用户跨页勾选所有匹配记录时同样适用。动作还可以在确认对话框内渲染自定义 HTML 表单。对于行级操作,可以用 @row_action 和 @link_row_action 取代自定义列格式化器。
权限与访问控制
Flask-Admin 的 can_* 类标志在 starlette-admin 中变成了按请求方法,因此授权决策可以取决于当前登录的用户。
| Flask-Admin | starlette-admin | 说明 |
|---|---|---|
is_accessible() |
is_accessible(request) |
在菜单中隐藏该视图,并阻止直接访问。 |
inaccessible_callback() |
由认证流程处理 | 未认证的请求会重定向到登录页。 |
can_create = False |
def can_create(self, request): return False |
can_edit 和 can_delete 采用相同模式。 |
can_view_details |
can_view_detail(request) |
详情页默认存在。 |
can_export |
can_export(request),外加 can_import(request) |
|
| 无对应概念 | can_access_field(request, field) |
按用户控制字段级可见性。 |
| 无对应概念 | is_action_allowed(request, name) |
提供按动作的授权。 |
使用 Flask-Admin 时,你需要自行集成 Flask-Login。starlette-admin 自带一个配有现成登录页的 AuthProvider,你只需针对自己的用户存储实现 login、logout 和 authenticate 方法。OAuthProvider 覆盖 OIDC 重定向流程。当前登录的用户在任何地方都可通过 request.state.admin_user 获取。
模型生命周期钩子
| Flask-Admin | starlette-admin |
|---|---|
on_model_change(form, model, is_created) |
before_create(request, data, obj) / before_edit(request, data, obj) |
after_model_change |
after_create / after_edit |
on_model_delete |
before_delete |
after_model_delete |
after_delete |
get_query / get_count_query |
get_list_query / get_count_query,特定于 SQLAlchemy 后端 |
handle_view_exception |
抛出 FormValidationError 或 ActionFailed |
除单个视图的钩子之外,事件系统还能让单个处理函数观察所有视图。Flask-Admin 没有对应的机制。
from starlette_admin.events import AdminEvent, AfterCreateContext
async def audit(ctx: AfterCreateContext) -> None: ...
admin.events.on(AdminEvent.AFTER_CREATE, audit)
自定义视图与索引页
| Flask-Admin | starlette-admin | 说明 |
|---|---|---|
BaseView + @expose("/") |
CustomView(menu_label=..., path=..., widget=...) |
使用部件组合页面,无需手写原始模板。 |
| 自定义模板渲染 | CustomView 子类 |
让你完全掌控路由和响应。 |
AdminIndexView |
Admin(index_view=...) |
用 StatWidget、ChartWidget、TableWidget 和布局部件构建仪表盘。 |
MenuLink |
Link 视图 |
例如,admin.add_link(Link(menu_label="Docs", url="https://...")) |
| 菜单中的分类 | DropDown 视图 |
在侧边栏中将视图分组。 |
FileAdmin |
不支持 | 文件和图片字段配合本地或 S3 存储处理附件。没有服务器文件浏览器。 |
内联模型
显式声明的类使每个内联模型都能使用完整的 ModelView 配置面:字段选择、校验以及复合外键支持。参见内联表单。
国际化
Flask-Admin 依赖 Flask-Babel 及其周边的 Flask 环境。starlette-admin 则改用配置对象:
from starlette_admin import I18nConfig
admin = Admin(engine, i18n_config=I18nConfig(default_locale="fr"))
支持时区的日期时间渲染也以同样的方式通过 TimezoneConfig 实现。参见国际化与时区。
切换后你能获得什么
- 异步技术栈。 在 FastAPI 和 Starlette 上原生运行,支持异步 SQLAlchemy、Beanie 和 Tortoise ORM。Flask-Admin 是同步的。
- 内置安全特性。 CSRF 保护、上传文件名净化、图片内容校验和导出行数限制在你实例化
Admin时即刻生效,你还可以在导出器上启用电子表格公式转义。参见安全性。 - 数据导入。 在写入任何数据之前,预览步骤会对每一行进行校验。Flask-Admin 没有导入功能。
- 仪表盘部件系统。 用 Python 构建索引页和自定义视图,而不是手写模板。
- 现代设计。 代码库持续积极维护,UI 精致,内置深色模式,并具备一流的类型提示。
需要适应的变化
- 显式的请求对象。 不存在隐式的全局请求上下文。每个钩子和权限方法都将
request作为参数接收。 - 异步处理函数。 钩子和动作都是协程,因此不要在其中进行阻塞调用,或将此类工作移到线程中执行。
- 没有
FileAdmin。 如果你的工作流依赖于浏览服务器文件系统,starlette-admin 无法满足这一需求。 - 没有创建或编辑模态框。 表单渲染为完整页面,而不是弹出式模态框。