Rustango:将 Django 的开箱即用能力带入 Rust
一个开箱即用的 Web 框架,它将 Django 的开发者体验——类型化 ORM、迁移、admin、认证以及管理命令——移植到异步 Rust 上,同时不放弃编译期保证。
我热爱 Django。多年来用它交付产品之后,这个框架的理念已经深深融入了我的思维方式:一个带类型的模型层、自动生成的迁移、开箱即用的后台管理,以及把这一切串联起来的管理 CLI。我同样热爱 Rust —— 那个拒绝让一整类 bug 进入生产环境的编译器,以及那个不需要垃圾回收器、也不需要专人照看的运行时。
很长一段时间里,这两份热爱活在互不相干的两个世界里。Rustango 是我把它们融合到一起的尝试:一个功能齐全的 Web 框架,把 Django 的开发者体验移植到异步 Rust 之上 —— 同时不放弃编译期保证。
一个读起来像 Django 的强类型 ORM
任何 Django 风格框架的核心都是模型层。在 Rustango 中,你在一个普通结构体上派生 Model,并用表名、主键和列约束对其进行标注。派生宏会生成一个带类型的列集合和一个可链式调用的 QuerySet——因此查询构建器是由编译器检查的,而不是在运行时才被发现的。
#[derive(Model, Default, Serialize, Deserialize)]
#[rustango(table = "blog_post", app = "blog")]
pub struct Post {
#[rustango(primary_key)]
pub id: Auto<i64>,
#[rustango(max_length = 200)]
pub title: String,
pub published: bool,
#[rustango(auto_now_add)]
pub created_at: Auto<DateTime<Utc>>,
}
// 一个可链式调用、经过类型检查的 QuerySet —— 列名都是真实的符号。
let recent = Post::objects()
.where_(Post::published.eq(true))
.order_by(&[("created_at", false)])
.fetch(pool)
.await?;
没有那种靠字符串拼写的查询 DSL 让你打错字。Post::published 是生成出来的符号;拼错它,构建就会失败。同一套列元数据还驱动着插入、更新,以及迁移引擎所消费的模式差异(schema diff)。
迁移,生成并应用
Rustango 模型携带一个框架可以与数据库进行比对的 SCHEMA。CLI 根据差异生成迁移文件,并按数据库逐一应用——而且因为 Rustango 从底层设计上就是多租户的,它清楚共享的注册表 schema 与每个租户的 schema 之间的区别。
cargo run -- makemigrations # diff models -> migration files
cargo run -- migrate-registry # apply the shared/registry schema
cargo run -- migrate-tenants # apply every tenant database
你无需亲手编写的后台管理界面
用 admin(...) 块为模型添加注解——列出列、排序、搜索——Rustango 就会为它渲染出一套完整的 CRUD 管理后台:带筛选和分页的列表视图、根据字段控件生成的创建/编辑表单,以及批量操作。正是这一项功能让 Django 用起来像开了作弊码,也是我在 Rust 中最怀念的东西。
#[rustango(
table = "blog_post", app = "blog",
admin(list_display = "title, published, created_at", ordering = "-created_at")
)]
pub struct Post { /* ... */ }
开箱即用:认证、会话、表单、CSRF、缓存
一个框架配得上开箱即用这个词,靠的是它交付的那些枯燥东西,让你永远不必再自己编写它们。Rustango 带来了签名会话、一整套密码/认证流程栈、带有 CSRF 保护的表单层、缓存(包括整页缓存)、信号、签名 URL,以及一个 manage::Cli,它将路由、多租户、迁移和你自己的命令连接到单个二进制文件中。路由构建在 Axum 和 Tokio 之上,因此其异步实现正是 Rust 生态系统早已信赖的成熟方案。
Django 的承诺从来都不是语法本身——而是这个框架早已替你做好了那些枯燥的决策。Rustango 延续了这一承诺,而编译器让你始终诚实。
这值得吗?
移植一个框架不是一个周末就能搞定的项目,而且相比 Python,Rust 在前期要求你付出更多。但回报是实实在在的:同一份模型定义同时驱动数据库、后台管理和 API,而借用检查器把一整类生产事故变成了编译期错误。如果你曾经希望 Django 能以 Rust 的速度、带着 Rust 的保证来运行,那么 Rustango 就是这个愿望在代码中的样子。