| Crates.io | reinhardt-web |
| lib.rs | reinhardt-web |
| version | 0.1.0-alpha.1 |
| created_at | 2026-01-23 11:02:44.077002+00 |
| updated_at | 2026-01-23 11:02:44.077002+00 |
| description | A full-stack API framework for Rust, inspired by Django and Django REST Framework |
| homepage | |
| repository | https://github.com/kent8192/reinhardt-web |
| max_upload_size | |
| id | 2064155 |
| size | 498,339 |
A composable full-stack API framework for Rust
Build with all the power of Django's batteries-included philosophy,
or compose only what you needβyour choice, your way.
You may be looking for:
Polylithic = Poly (many) + Lithic (building blocks) Unlike monolithic frameworks that force you to use everything, Reinhardt lets you compose your perfect stack from independent, well-tested components.
Reinhardt brings together the best of three worlds:
| Inspiration | What We Borrowed | What We Improved |
|---|---|---|
| π Django | Batteries-included philosophy, ORM design, admin panel | Feature flags for composable builds, Rust's type safety |
| π― Django REST | Serializers, ViewSets, permissions | Compile-time validation, zero-cost abstractions |
| β‘ FastAPI | DI system, automatic OpenAPI | Native Rust performance, no runtime overhead |
| ποΈ SQLAlchemy | QuerySet patterns, relationship handling | Type-safe query builder, compile-time validation |
Result: A framework that's familiar to Python developers, but with Rust's performance and safety guarantees.
See Available Components for complete list and Getting Started for examples.
Reinhardt is a modular framework. Choose your starting point:
Note on Crate Naming:
The main Reinhardt crate is published on crates.io as reinhardt-web, but you import it as reinhardt in your code using the package attribute.
Get all features with zero configuration:
[dependencies]
# Import as 'reinhardt', published as 'reinhardt-web'
# Default enables ALL features (full bundle)
reinhardt = { version = "0.1.0-alpha.1", package = "reinhardt-web" }
Includes: Database, Auth, REST API, Admin, GraphQL, WebSockets, Cache, i18n, Mail, Sessions, Static Files, Storage
Binary: ~50+ MB | Compile: Slower, but everything works out of the box
Then use in your code:
use reinhardt::prelude::*;
use reinhardt::{Request, Response, StatusCode};
For most projects that don't need all features:
[dependencies]
reinhardt = { version = "0.1.0-alpha.1", package = "reinhardt-web", default-features = false, features = ["standard"] }
Includes: Core, Database (PostgreSQL), REST API, Auth, Middleware, Pages (WASM Frontend with SSR)
Binary: ~20-30 MB | Compile: Medium
Lightweight and fast, perfect for simple APIs:
[dependencies]
reinhardt = { version = "0.1.0-alpha.1", package = "reinhardt-web", default-features = false, features = ["minimal"] }
Includes: HTTP, routing, DI, parameter extraction, server
Binary: ~5-10 MB | Compile: Very fast
Install only the components you need:
[dependencies]
# Core components
reinhardt-http = "0.1.0-alpha.1"
reinhardt-urls = "0.1.0-alpha.1"
# Optional: Database
reinhardt-db = "0.1.0-alpha.1"
# Optional: Authentication
reinhardt-auth = "0.1.0-alpha.1"
# Optional: REST API features
reinhardt-rest = "0.1.0-alpha.1"
# Optional: Admin panel
reinhardt-admin = "0.1.0-alpha.1"
# Optional: Advanced features
reinhardt-graphql = "0.1.0-alpha.1"
reinhardt-websockets = "0.1.0-alpha.1"
π For a complete list of available crates and feature flags, see the Feature Flags Guide.
cargo install reinhardt-admin-cli
# Create a RESTful API project (default)
reinhardt-admin startproject my-api
cd my-api
This generates a complete project structure:
my-api/
βββ Cargo.toml
βββ src/
β βββ lib.rs
β βββ config.rs
β βββ apps.rs
β βββ config/
β β βββ settings.rs
β β βββ settings/
β β β βββ base.rs
β β β βββ local.rs
β β β βββ staging.rs
β β β βββ production.rs
β β βββ urls.rs
β β βββ apps.rs
β βββ bin/
β βββ manage.rs
βββ README.md
Alternative: Create a reinhardt-pages Project (WASM + SSR)
For a modern WASM-based frontend with SSR:
# Create a pages project
reinhardt-admin startproject my-app --with-pages
cd my-app
# Install WASM build tools (first time only)
cargo make install-wasm-tools
# Build WASM and start development server
cargo make dev
# Visit http://127.0.0.1:8000/
# Using the manage command
cargo run --bin manage runserver
# Server will start at http://127.0.0.1:8000
Auto-Reload Support:
For automatic reloading on code changes (requires bacon):
# Install bacon
cargo install --locked bacon
# Run with auto-reload
bacon runserver
# Or use cargo make
cargo make watch
# For tests
bacon test
# Create a RESTful API app (default)
cargo run --bin manage startapp users
# Or explicitly specify type
cargo run --bin manage startapp users --restful
# Create a Pages app (WASM + SSR)
cargo run --bin manage startapp dashboard --with-pages
This creates an app structure:
users/
βββ lib.rs
βββ models.rs
βββ models/
βββ views.rs
βββ views/
βββ serializers.rs
βββ serializers/
βββ admin.rs
βββ urls.rs
βββ tests.rs
Edit your app's urls.rs:
// users/urls.rs
use reinhardt::ServerRouter;
use super::views;
pub fn url_patterns() -> ServerRouter {
ServerRouter::new()
.endpoint(views::list_users)
.endpoint(views::get_user)
.endpoint(views::create_user)
}
Include in src/config/urls.rs:
// src/config/urls.rs
use reinhardt::prelude::*;
use reinhardt::routes;
#[routes]
pub fn routes() -> ServerRouter {
ServerRouter::new()
.mount("/api/", users::urls::url_patterns())
}
The #[routes] attribute macro automatically registers this function with the
framework for discovery via the inventory crate.
Note: The reinhardt::prelude includes commonly used types. Key exports include:
Always Available:
Router, DefaultRouter, ServerRouter, View, ListView, DetailViewViewSet, ModelViewSet, ReadOnlyModelViewSetStatusCodeFeature-Dependent:
core feature: Request, Response, Handler, Middleware, Signals (post_save, pre_save, etc.)database feature: Model, DatabaseConnection, F, Q, Transaction, atomic, Database functions (Concat, Upper, Lower, Now, CurrentDate), Window functions (Window, RowNumber, Rank, DenseRank), Constraints (UniqueConstraint, CheckConstraint, ForeignKeyConstraint)auth feature: User, UserManager, GroupManager, Permission, ObjectPermissionminimal, standard, or di features: Body, Cookie, Header, Json, Path, Queryrest feature: Serializers, Parsers, Pagination, Throttling, Versioningadmin feature: Admin panel componentscache feature: Cache, InMemoryCachesessions feature: Session, AuthenticationMiddlewareFor a complete list, see Feature Flags Guide.
For a complete step-by-step guide, see Getting Started.
Configure database in settings/base.toml:
debug = true
secret_key = "your-secret-key-for-development"
[database]
engine = "postgresql"
host = "localhost"
port = 5432
name = "mydb"
user = "postgres"
password = "postgres"
Settings are automatically loaded in src/config/settings.rs:
// src/config/settings.rs
use reinhardt::conf::settings::builder::SettingsBuilder;
use reinhardt::conf::settings::profile::Profile;
use reinhardt::conf::settings::sources::{DefaultSource, LowPriorityEnvSource, TomlFileSource};
use reinhardt::core::Settings;
use std::env;
use std::path::PathBuf;
use std::str::FromStr;
pub fn get_settings() -> Settings {
let profile_str = env::var("REINHARDT_ENV").unwrap_or_else(|_| "local".to_string());
let profile = Profile::from_str(&profile_str).unwrap_or(Profile::Development);
let base_dir = env::current_dir().expect("Failed to get current directory");
let settings_dir = base_dir.join("settings");
let merged = SettingsBuilder::new()
.profile(profile)
.add_source(
DefaultSource::new()
.with_value("debug", serde_json::Value::Bool(false))
.with_value("language_code", serde_json::Value::String("en-us".to_string()))
.with_value("time_zone", serde_json::Value::String("UTC".to_string()))
)
.add_source(LowPriorityEnvSource::new().with_prefix("REINHARDT_"))
.add_source(TomlFileSource::new(settings_dir.join("base.toml")))
.add_source(TomlFileSource::new(settings_dir.join(format!("{}.toml", profile_str))))
.build()
.expect("Failed to build settings");
merged.into_typed().expect("Failed to convert settings to Settings struct")
}
Environment Variable Sources:
Reinhardt provides two types of environment variable sources with different priorities:
EnvSource (priority: 100) - High priority environment variables that override TOML files
.add_source(EnvSource::new().with_prefix("REINHARDT_"))
LowPriorityEnvSource (priority: 40) - Low priority environment variables that fall back to TOML files
.add_source(LowPriorityEnvSource::new().with_prefix("REINHARDT_"))
Priority Order:
EnvSource: Environment Variables > {profile}.toml > base.toml > DefaultsLowPriorityEnvSource (shown above): {profile}.toml > base.toml > Environment Variables > DefaultsChoose EnvSource when environment variables should always take precedence (e.g., production deployments).
Choose LowPriorityEnvSource when TOML files should be the primary configuration source (e.g., development).
See Settings Documentation for more details.
Using the Built-in DefaultUser:
Reinhardt provides a ready-to-use DefaultUser implementation (requires argon2-hasher feature):
// users/models.rs
use reinhardt::prelude::*;
use reinhardt::DefaultUser;
// Re-export DefaultUser as User for your app
pub type User = DefaultUser;
// DefaultUser includes:
// - id: Uuid (primary key)
// - username: String
// - email: String
// - password_hash: Option<String>
// - first_name: String
// - last_name: String
// - is_active: bool
// - is_staff: bool
// - is_superuser: bool
// - last_login: Option<DateTime<Utc>>
// - date_joined: DateTime<Utc>
// DefaultUser implements:
// - BaseUser trait (authentication methods)
// - FullUser trait (full user information)
// - PermissionsMixin trait (permission management)
// - Model trait (database operations)
Defining Custom User Models:
If you need custom fields, define your own model:
// users/models.rs
use reinhardt::prelude::*;
use serde::{Serialize, Deserialize};
use chrono::{DateTime, Utc};
#[model(app_label = "users", table_name = "users")]
pub struct CustomUser {
#[field(primary_key = true)]
pub id: i64,
#[field(max_length = 255)]
pub email: String,
#[field(max_length = 100)]
pub username: String,
#[field(default = true)]
pub is_active: bool,
#[field(auto_now_add = true)]
pub created_at: DateTime<Utc>,
// Add custom fields
#[field(max_length = 50, null = true)]
pub phone_number: Option<String>,
}
Model Attribute Macro:
The #[model(...)] attribute automatically generates:
Model trait (includes #[derive(Model)] functionality)User::field_email(), User::field_username(), etc.Note: When using #[model(...)], you do NOT need to add #[derive(Model)] separately,
as it is automatically applied by the #[model(...)] attribute.
Field Attributes:
#[field(primary_key = true)] - Mark as primary key#[field(max_length = 255)] - Set maximum length for string fields#[field(default = value)] - Set default value#[field(auto_now_add = true)] - Auto-populate timestamp on creation#[field(auto_now = true)] - Auto-update timestamp on save#[field(null = true)] - Allow NULL values#[field(unique = true)] - Enforce uniqueness constraintFor a complete list of field attributes, see the Field Attributes Guide.
The generated field accessors enable type-safe field references in queries:
// Generated by #[model(...)] for DefaultUser
impl DefaultUser {
pub const fn field_id() -> FieldRef<DefaultUser, Uuid> { FieldRef::new("id") }
pub const fn field_username() -> FieldRef<DefaultUser, String> { FieldRef::new("username") }
pub const fn field_email() -> FieldRef<DefaultUser, String> { FieldRef::new("email") }
pub const fn field_is_active() -> FieldRef<DefaultUser, bool> { FieldRef::new("is_active") }
pub const fn field_is_staff() -> FieldRef<DefaultUser, bool> { FieldRef::new("is_staff") }
pub const fn field_date_joined() -> FieldRef<DefaultUser, DateTime<Utc>> { FieldRef::new("date_joined") }
// ... other fields
}
Advanced Query Examples:
use reinhardt::prelude::*;
use reinhardt::DefaultUser;
// Django-style F/Q object queries with type-safe field references
async fn complex_user_query() -> Result<Vec<DefaultUser>, Box<dyn std::error::Error>> {
// Q objects with type-safe field references (using generated field accessors)
let active_query = Q::new()
.field("is_active").eq(true)
.and(Q::new().field("date_joined").gte(Now::new()));
// Database functions with type-safe field references
let email_lower = Lower::new(DefaultUser::field_email().into());
let username_upper = Upper::new(DefaultUser::field_username().into());
// Aggregations using field accessors
let user_count = Aggregate::count(DefaultUser::field_id().into());
let latest_joined = Aggregate::max(DefaultUser::field_date_joined().into());
// Window functions for ranking
let rank_by_join_date = Window::new()
.partition_by(vec![DefaultUser::field_is_active().into()])
.order_by(vec![(DefaultUser::field_date_joined().into(), "DESC")])
.function(RowNumber::new());
todo!("Execute query with these components")
}
// Transaction support
async fn create_user_with_transaction(
conn: &DatabaseConnection,
user_data: CreateUserRequest
) -> Result<User, Box<dyn std::error::Error>> {
// Transaction with automatic rollback on error
transaction(conn, |_tx| async move {
let user = User::create(user_data).await?;
log_user_creation(&user).await?;
Ok(user)
}).await
}
Note: Reinhardt uses SeaQuery v1.0.0-rc for SQL operations. The #[derive(Model)] macro automatically generates Model trait implementations, type-safe field accessors, and global model registry registration.
Register in src/config/apps.rs:
// src/config/apps.rs
use reinhardt::installed_apps;
// The installed_apps! macro generates:
// - An enum InstalledApp with variants for each app
// - Implementation of conversion traits (From, Into, Display)
// - A registry for app configuration and discovery
//
// Note: Unlike Django's INSTALLED_APPS, this macro is for user apps only.
// Built-in framework features (auth, sessions, admin, etc.) are enabled via
// Cargo feature flags, not through installed_apps!.
//
// Example:
// [dependencies]
// reinhardt = { version = "0.1", features = ["auth", "sessions", "admin"] }
//
// This enables:
// - Automatic app discovery for migrations, admin panel, etc.
// - Type-safe app references throughout your code
// - Centralized app configuration
installed_apps! {
users: "users",
}
pub fn get_installed_apps() -> Vec<String> {
InstalledApp::all_apps()
}
Reinhardt provides Django-style user models with BaseUser and FullUser traits, along with comprehensive user management through UserManager.
Note: Reinhardt includes a built-in DefaultUser implementation. You can use it directly or define your own user model as shown below.
User Management Example:
use reinhardt::prelude::*;
// Create and manage users with UserManager
async fn manage_users() -> Result<(), Box<dyn std::error::Error>> {
let hasher = Argon2Hasher::new();
let user_manager = UserManager::new(hasher);
// Create a new user
let user = user_manager.create_user(CreateUserData {
username: "alice".to_string(),
email: "alice@example.com".to_string(),
password: "secure_password".to_string(),
first_name: Some("Alice".to_string()),
last_name: Some("Smith".to_string()),
}).await?;
// Update user information
user_manager.update_user(user.id, UpdateUserData {
email: Some("alice.smith@example.com".to_string()),
is_active: Some(true),
..Default::default()
}).await?;
// Manage groups and permissions
let group_manager = GroupManager::new();
let editors = group_manager.create_group(CreateGroupData {
name: "editors".to_string(),
}).await?;
// Assign object-level permissions
let permission = ObjectPermission::new("edit", user.id, article.id);
let perm_checker = ObjectPermissionChecker::new();
if perm_checker.has_permission(&user, "edit", &article).await? {
// User can edit the article
}
Ok(())
}
Use the built-in DefaultUser in users/models.rs:
// users/models.rs
use reinhardt::DefaultUser;
// Re-export DefaultUser as your User type
pub type User = DefaultUser;
// DefaultUser already implements:
// - BaseUser trait (authentication methods)
// - FullUser trait (username, email, first_name, last_name, etc.)
// - PermissionsMixin trait (permission management)
// - Model trait (database operations)
For Custom User Models:
If you need additional fields beyond DefaultUser, define your own:
// users/models.rs
use reinhardt::auth::{BaseUser, FullUser, PermissionsMixin};
use uuid::Uuid;
use chrono::{DateTime, Utc};
use serde::{Serialize, Deserialize};
#[model(app_label = "users", table_name = "users")]
pub struct CustomUser {
#[field(primary_key = true)]
pub id: Uuid,
#[field(max_length = 150)]
pub username: String,
#[field(max_length = 255)]
pub email: String,
pub password_hash: Option<String>,
#[field(max_length = 150)]
pub first_name: String,
#[field(max_length = 150)]
pub last_name: String,
#[field(default = true)]
pub is_active: bool,
#[field(default = false)]
pub is_staff: bool,
#[field(default = false)]
pub is_superuser: bool,
pub last_login: Option<DateTime<Utc>>,
#[field(auto_now_add = true)]
pub date_joined: DateTime<Utc>,
// Custom fields
#[field(max_length = 20, null = true)]
pub phone_number: Option<String>,
}
impl BaseUser for CustomUser {
type PrimaryKey = Uuid;
fn get_username_field() -> &'static str { "username" }
fn get_username(&self) -> &str { &self.username }
fn password_hash(&self) -> Option<&str> { self.password_hash.as_deref() }
fn set_password_hash(&mut self, hash: String) { self.password_hash = Some(hash); }
fn last_login(&self) -> Option<DateTime<Utc>> { self.last_login }
fn set_last_login(&mut self, time: DateTime<Utc>) { self.last_login = Some(time); }
fn is_active(&self) -> bool { self.is_active }
}
impl FullUser for CustomUser {
fn username(&self) -> &str { &self.username }
fn email(&self) -> &str { &self.email }
fn first_name(&self) -> &str { &self.first_name }
fn last_name(&self) -> &str { &self.last_name }
fn is_staff(&self) -> bool { self.is_staff }
fn is_superuser(&self) -> bool { self.is_superuser }
fn date_joined(&self) -> DateTime<Utc> { self.date_joined }
}
Use JWT authentication in your app's views/profile.rs:
// users/views/profile.rs
use reinhardt::auth::{JwtAuth, BaseUser};
use reinhardt::{Request, Response, StatusCode, ViewResult, get};
use reinhardt::db::DatabaseConnection;
use std::sync::Arc;
use crate::models::User;
#[get("/profile", name = "get_profile")]
pub async fn get_profile(
req: Request,
#[inject] db: Arc<DatabaseConnection>,
) -> ViewResult<Response> {
// Extract JWT token from Authorization header
let auth_header = req.headers.get("authorization")
.and_then(|h| h.to_str().ok())
.ok_or("Missing Authorization header")?;
let token = auth_header.strip_prefix("Bearer ")
.ok_or("Invalid Authorization header format")?;
// Verify token and get user ID
let jwt_auth = JwtAuth::new(b"your-secret-key");
let claims = jwt_auth.verify_token(token)?;
// Load user from database using claims.user_id
let user = User::find_by_id(&db, &claims.user_id).await?;
// Check if user is active
if !user.is_active() {
return Err("User account is inactive".into());
}
// Return user profile as JSON
let json = serde_json::to_string(&user)?;
Ok(Response::new(StatusCode::OK)
.with_body(json))
}
Reinhardt uses HTTP method decorators to define endpoints:
Use #[get], #[post], #[put], #[delete] to define routes:
use reinhardt::{get, post, Request, Response, ViewResult};
use serde_json::json;
#[get("/")]
pub async fn hello(_req: Request) -> ViewResult<Response> {
Ok(Response::ok().with_body("Hello, World!"))
}
#[post("/users")]
pub async fn create_user(_req: Request) -> ViewResult<Response> {
let body = json!({"status": "created"});
Response::ok().with_json(&body).map_err(Into::into)
}
Features:
#[inject]Combine HTTP method decorators with #[inject] for automatic dependency injection:
use reinhardt::{get, Request, Response, StatusCode, ViewResult};
use reinhardt::db::DatabaseConnection;
use std::sync::Arc;
#[get("/users/{id}/", name = "get_user")]
pub async fn get_user(
req: Request,
#[inject] db: Arc<DatabaseConnection>, // Automatically injected
) -> ViewResult<Response> {
let id = req.path_params.get("id")
.ok_or("Missing id")?
.parse::<i64>()?;
// Use injected database connection
let user = db.query("SELECT * FROM users WHERE id = $1")
.bind(id)
.fetch_one()
.await?;
let json = serde_json::to_string(&user)?;
Ok(Response::new(StatusCode::OK)
.with_body(json))
}
Dependency Injection Features:
#[inject] attribute#[inject(cache = false)]Result Type:
All view functions use ViewResult<T> as the return type:
use reinhardt::ViewResult; // Pre-defined result type
In your app's views/user.rs:
// users/views/user.rs
use reinhardt::{Request, Response, StatusCode, ViewResult, get};
use reinhardt::db::DatabaseConnection;
use crate::models::User;
use std::sync::Arc;
#[get("/users/{id}/", name = "get_user")]
pub async fn get_user(
req: Request,
#[inject] db: Arc<DatabaseConnection>,
) -> ViewResult<Response> {
// Extract path parameter from request
let id = req.path_params.get("id")
.ok_or("Missing id parameter")?
.parse::<i64>()
.map_err(|_| "Invalid id format")?;
// Extract query parameters (e.g., ?include_inactive=true)
let include_inactive = req.query_params.get("include_inactive")
.and_then(|v| v.parse::<bool>().ok())
.unwrap_or(false);
// Fetch user from database using injected connection
let user = User::find_by_id(&db, id).await?;
// Check active status if needed
if !include_inactive && !user.is_active {
return Err("User is inactive".into());
}
// Return as JSON
let json = serde_json::to_string(&user)?;
Ok(Response::new(StatusCode::OK)
.with_body(json))
}
Register route with path parameter in urls.rs:
// users/urls.rs
use reinhardt::ServerRouter;
use super::views;
pub fn url_patterns() -> ServerRouter {
ServerRouter::new()
.endpoint(views::get_user) // Path defined in #[get("/users/{id}/")]
}
In your app's serializers/user.rs:
// users/serializers/user.rs
use serde::{Serialize, Deserialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Validate)]
pub struct CreateUserRequest {
#[validate(email)]
pub email: String,
#[validate(length(min = 3, max = 50))]
pub username: String,
#[validate(length(min = 8))]
pub password: String,
}
#[derive(Serialize, Deserialize)]
pub struct UserResponse {
pub id: i64,
pub username: String,
pub email: String,
pub is_active: bool,
}
impl From<User> for UserResponse {
fn from(user: User) -> Self {
UserResponse {
id: user.id,
username: user.username,
email: user.email,
is_active: user.is_active,
}
}
}
In your app's views/user.rs:
// users/views/user.rs
use reinhardt::{Request, Response, StatusCode, ViewResult, post};
use reinhardt::db::DatabaseConnection;
use crate::models::User;
use crate::serializers::{CreateUserRequest, UserResponse};
use validator::Validate;
use std::sync::Arc;
#[post("/users", name = "create_user")]
pub async fn create_user(
mut req: Request,
#[inject] db: Arc<DatabaseConnection>,
) -> ViewResult<Response> {
// Parse request body
let body_bytes = std::mem::take(&mut req.body);
let create_req: CreateUserRequest = serde_json::from_slice(&body_bytes)?;
// Validate request
create_req.validate()?;
// Create user
let mut user = User {
id: 0, // Will be set by database
username: create_req.username,
email: create_req.email,
password_hash: None,
is_active: true,
created_at: Utc::now(),
};
// Hash password using BaseUser trait
user.set_password(&create_req.password)?;
// Save to database using injected connection
user.save(&db).await?;
// Convert to response
let response_data = UserResponse::from(user);
let json = serde_json::to_string(&response_data)?;
Ok(Response::new(StatusCode::CREATED)
.with_body(json))
}
Reinhardt offers modular components you can mix and match:
| Component | Crate Name | Features |
|---|---|---|
| Core | ||
| Core Types | reinhardt-core |
Core traits, types, macros (Model, endpoint) |
| HTTP & Routing | reinhardt-http |
Request/Response, HTTP handling |
| URL Routing | reinhardt-urls |
Function-based and class-based routes |
| Server | reinhardt-server |
HTTP server implementation |
| Middleware | reinhardt-dispatch |
Middleware chain, signal dispatch |
| Configuration | reinhardt-conf |
Settings management, environment loading |
| Commands | reinhardt-commands |
Management CLI tools (startproject, etc.) |
| Shortcuts | reinhardt-shortcuts |
Common utility functions |
| Database | ||
| ORM | reinhardt-db |
SeaQuery v1.0.0-rc integration |
| Authentication | ||
| Auth | reinhardt-auth |
JWT, Token, Session, Basic auth, User models |
| REST API | ||
| Serializers | reinhardt-rest |
serde/validator integration, ViewSets |
| Forms | ||
| Forms | reinhardt-forms |
Form handling and validation |
| Advanced | ||
| Admin Panel | reinhardt-admin |
Django-style admin interface |
| Plugin System | reinhardt-dentdelion |
Static & WASM plugin support, CLI management |
| Background Tasks | reinhardt-tasks |
Task queues (Redis, RabbitMQ, SQLite) |
| GraphQL | reinhardt-graphql |
Schema generation, subscriptions |
| WebSockets | reinhardt-websockets |
Real-time communication |
| i18n | reinhardt-i18n |
Multi-language support |
| Testing | ||
| Test Utilities | reinhardt-test |
Testing helpers, fixtures, TestContainers |
For detailed feature flags within each crate, see the Feature Flags Guide.
For AI Assistants: See CLAUDE.md for project-specific coding standards, testing guidelines, and development conventions.
Reinhardt is a community-driven project. Here's where you can get help:
Before asking, please check:
We love contributions! Please read our Contributing Guide to get started.
Quick links:
Licensed under either of:
at your option.
This project is inspired by:
See THIRD-PARTY-NOTICES for full attribution.
Note: This project is not affiliated with or endorsed by the Django Software Foundation, Encode OSS Ltd., SebastiΓ‘n RamΓrez (FastAPI author), or Michael Bayer (SQLAlchemy author).