Rust 2026-07-10·Ievgenii Svyryd

Rustango: приносимо «батарейки» Django у Rust

Веб-фреймворк «з батарейками в комплекті», що переносить досвід розробника з Django — типізований ORM, міграції, admin, автентифікацію та команди керування — в асинхронний Rust, не відмовляючись від гарантій на етапі компіляції.

Rustango: приносимо «батарейки» Django у Rust

Я люблю Django. За роки випуску продуктів на ньому філософія фреймворку вбудувалася в те, як я мислю: типізований шар моделей, міграції, що пишуть себе самі, адмінка, яку ти отримуєш безкоштовно, і CLI для управління, що зв'язує все це докупи. Я також люблю Rust - компілятор, який відмовляється пропускати цілий клас багів у продакшн, і рантайм, якому не потрібен ані збирач сміття, ані нянька.

Довгий час ці дві любові жили в окремих світах. Rustango - це моя спроба звести їх разом: веб-фреймворк із батарейками в комплекті, який переносить досвід розробника Django на асинхронний Rust - не відмовляючись від гарантій на етапі компіляції.

Типізований ORM, що читається як Django

Серцем будь-якого фреймворку в стилі Django є шар моделей. У Rustango ви виводите Model на звичайній структурі й анотуєте її таблицею, первинним ключем та обмеженнями стовпців. Макрос derive генерує типізований набір стовпців і ланцюжковий 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>>,
}

// A chainable, type-checked QuerySet - column names are real symbols.
let recent = Post::objects()
    .where_(Post::published.eq(true))
    .order_by(&[("created_at", false)])
    .fetch(pool)
    .await?;

Немає рядкового (stringly-typed) DSL запитів, у якому можна зробити описку. Post::published - це згенерований символ; напишіть його з помилкою, і збірка впаде. Ті самі метадані стовпців живлять вставки, оновлення та diff схеми, який споживає рушій міграцій.

Міграції, згенеровані та застосовані

Моделі Rustango несуть SCHEMA, яку фреймворк може порівнювати з базою даних. CLI генерує файли міграцій з різниці й застосовує їх для кожної бази - і оскільки Rustango мультитенантний з самого фундаменту, він знає різницю між спільною схемою реєстру та схемою кожного тенанта.

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, кешування

Фреймворк заслуговує на слово batteries-included завдяки тим нудним речам, які він постачає, щоб ви ніколи не писали їх знову. Rustango приносить підписані сесії, стек пароля/потоку автентифікації, шар форм із CSRF-захистом, кеш (включно з повносторінковим кешуванням), сигнали, підписані URL та manage::Cli, який поєднує маршрутизацію, мультитенантність, міграції та ваші власні команди в один бінарний файл. Маршрутизація базується на Axum і Tokio, тож асинхронна історія — це зріле рішення, якому екосистема Rust уже довіряє.

Обіцянка Django ніколи не полягала в синтаксисі — вона полягала в тому, що фреймворк уже ухвалив за вас усі нудні рішення. Rustango дотримується цієї обіцянки, а компілятор тримає вас у чесних рамках.

Чи воно було того варте?

Портування фреймворку - це не проєкт на вихідні, і Rust вимагає більше зусиль наперед, ніж Python. Але віддача реальна: одне й те саме визначення моделі керує базою даних, адмінкою та API, а borrow checker перетворює цілу категорію продакшн-інцидентів на помилки компіляції. Якщо ви коли-небудь мріяли, щоб Django працював зі швидкістю Rust і гарантіями Rust, Rustango - це те, як ця мрія виглядає в коді.

Зв'язатися →