为 FastAPI & Starlette 打造
可扩展的管理界面
根据你的 SQLAlchemy、SQLModel、Beanie、MongoEngine 或 Tortoise ORM 模型生成完整的管理界面。starlette-admin 基于 Tabler UI 组件库构建,为你提供列表视图、自动生成的表单、数据导出以及安全的身份认证。整个界面都可以用 Python 配置,无需编写任何前端代码。
pip install starlette-admin
内置功能
你所需的一切开箱即用。每项核心功能都带有完善的扩展点文档,方便你按自己的需求进行定制。
表格
通过分页、多列排序和可保留状态的 URL 浏览、搜索并排序你的数据。还可以直接在列表视图中行内编辑字段。
过滤器
在界面中构建嵌套的 AND/OR 查询,针对文本、数字、日期和布尔值提供感知类型的操作符。
表单与上传
为 25 种以上的字段类型以及关联数据自动生成表单。文件上传可直接发送到本地存储或 S3 存储。
动作
使用标准 Python 装饰器创建批量与行级操作。每次执行都可设置确认弹窗和自定义载荷表单加以保护。
导出与导入
将记录导出为 CSV、Excel、JSON、PDF 或 tablib 支持的任何格式。批量导入数据时提供先预览后写入的向导,在写入数据库之前逐行校验。
认证与安全
接入你已有的身份认证方案。默认配置即可安全上生产,包括 CSRF 防护以及内置的导出与导入限制。
内联表单
就地管理关联数据。在父模型表单内直接编辑子记录,无需离开当前页面。
仪表盘
使用内置的统计、图表和表格部件搭建首页,也可以将其完全替换为自定义视图。
国际化与时区
以多种语言呈现管理界面,开箱即用地提供符合区域设置的格式化和精确的时区处理。
一切皆 Python
使用纯 Python API 构建完整的管理界面,专为快速开发、语法可读和长期可维护而设计。
挂载管理后台
注册一个模型,并把管理后台挂载到任意 FastAPI 或 Starlette 应用上。然后运行 fastapi dev 并打开 /admin。
from fastapi import FastAPI
from sqlalchemy import create_engine
from starlette_admin.contrib.sqla import Admin, ModelView
from models import Base, Post
engine = create_engine("sqlite:///blog.db")
Base.metadata.create_all(engine)
app = FastAPI()
admin = Admin(engine, title="Blog Admin", secret_key="change-me")
admin.add_view(ModelView(Post, icon="fa fa-newspaper"))
admin.mount_to(app)
视图
使用简单的类属性即可设置搜索、排序、默认排列顺序和导出格式。并通过 form_layout 排列新建与编辑表单。
from starlette_admin.contrib.sqla import ModelView
class PostView(ModelView):
fields = ["id", "title", "author", "content", "published", "created_at"]
searchable_fields = ["title", "content"]
fields_default_sort = [("created_at", True)]
exporters = ["csv", "xlsx", "json"]
form_layout = [
("title", "author"),
"content",
("published", "created_at"),
]
admin.add_view(PostView(Post, icon="fa fa-newspaper"))
字段
重写任何自动检测的字段,以控制校验、页面级可见性,以及 starlette-admin 读取和展示值的方式。
from starlette_admin import DateTimeField, RequestAction, StringField, TextAreaField
from starlette_admin.contrib.sqla import ModelView
class PostView(ModelView):
fields = [
"id",
StringField("title", required=True, help_text="Shown on the blog"),
TextAreaField("content", exclude_from_list=True),
StringField(
"author_email",
getter=lambda request, obj: obj.author.email,
formatter={RequestAction.LIST: lambda request, value: value or "unset"},
),
DateTimeField("created_at", read_only=True, exclude_from_create=True),
]
过滤器
使用符合业务规则的自定义过滤器扩展内置查询构建器。你可以把所需的操作直接应用到底层数据库模型上。
from datetime import datetime
from typing import Any
from starlette_admin.contrib.sqla import ModelView
from starlette_admin.filters.base import BaseFilter, FilterApplyContext, FilterDataType
class ActiveThisMonthFilter(BaseFilter):
name = "this_month"
label = "Created this month"
data_type = FilterDataType.NONE # No value input. The range comes from now().
def apply(self, ctx: FilterApplyContext) -> Any:
now = datetime.utcnow()
start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
col = getattr(ctx.view.model, ctx.field_name)
return col.between(start, now)
class ProductView(ModelView):
fields = [
DateTimeField(
"created_at",
filters=[ActiveThisMonthFilter, ...],
),
]
动作
只需一个装饰器即可附加业务操作。确认弹窗、自定义表单和 Flash 消息都已内置于框架之中。
from starlette.requests import Request
from starlette_admin import ActionSelection, action, flash
from starlette_admin.contrib.sqla import ModelView
class ArticleView(ModelView):
actions = ["publish", "delete"]
@action(
name="publish",
text="Mark as published",
confirmation="Publish the selected articles?",
submit_btn_text="Yes, publish",
)
async def publish(self, request: Request, selection: ActionSelection) -> None:
articles = await selection.rows()
for article in articles:
article.published = True
flash(request, f"{len(articles)} articles published.", "success")
认证
围绕你自己的凭据校验逻辑实现三个标准方法。登录页、会话和重定向都由 starlette-admin 替你处理。
from starlette.requests import Request
from starlette_admin.auth import AdminUser, AuthProvider, LoginFailed
class MyAuthProvider(AuthProvider):
async def login(self, username, password, remember_me, request: Request) -> None:
if not await check_credentials(username, password):
raise LoginFailed("Invalid username or password")
request.session["username"] = username
async def authenticate(self, request: Request) -> AdminUser | None:
if username := request.session.get("username"):
return AdminUser(username=username)
return None
async def logout(self, request: Request) -> None:
request.session.clear()
admin = Admin(engine, auth_provider=MyAuthProvider(), secret_key=SECRET)
仪表盘
使用统计、图表和表格部件组合出管理首页,它们会在每次请求时查询实时数据。
from starlette_admin import CardRowWidget, ChartWidget, CustomView, StatWidget
dashboard = CardRowWidget(
children=[
StatWidget(title="Orders", value_callback=count_orders, countup=True),
StatWidget(title="Revenue", value_callback=sum_revenue, color="success"),
ChartWidget(title="Sales", chart_type="area", series_callback=sales_series),
]
)
admin = Admin(
engine,
title="Shop Admin",
secret_key="change-me",
index_view=CustomView(menu_label="Dashboard", icon="fa fa-home", widget=dashboard),
)
插件与扩展
每一层都可以替换。将功能打包为独立自足的插件,或挂接到专门的扩展点,让框架贴合你的业务领域。
挂接到任意组件
预定义的接口让你可以独立地替换或扩展每个关注点。子类化所需的基类并注册即可。从认证流程到导出格式,一切皆可定制。
- 自定义字段
BaseField - 自定义过滤器
BaseFilter - 导出器
BaseExporter - 导入器
BaseImporter - 主题
BaseTheme - 认证提供方
BaseAuthProvider - 存储后端
BaseStorage - 仪表盘部件
BaseWidget - 模板
templates_dir