Tutorial Part 6: Static Files, Favicon, and Middleware Stack
In Part 6, we examine Djangors’ middleware architecture (security_headers_layer, SessionLayer, csrf_layer), static asset management (favicon_routes), and static file collection (collectstatic).
Note
All middleware configuration code matches
examples/polls/src/main.rsandexamples/polls/src/urls.rs.
1. Configuring the Tower Middleware Stack
In Djangors, middleware is built using standard Rust Tower layers in src/main.rs:
fn main() {
let settings = djangors_core::DjangorsSettings::default();
let router_service = djangors_core::router::RouterService::new(djangors_core::Router::new(), settings.debug);
let secret_key = if settings.secret_key.is_empty() {
"dev-only-secret-key-at-least-32-bytes-long-for-signing-cookies".to_string()
} else {
settings.secret_key.clone()
};
let service = tower::ServiceBuilder::new()
.layer(djangors_core::middleware::security_headers_layer())
.layer(djangors_sessions::SessionLayer::new(
djangors_sessions::SignedCookieStore::new(secret_key.as_bytes()),
))
.layer(djangors_core::middleware::csrf_layer())
.service(router_service);
}
Layer Breakdown
security_headers_layer(): Injects HTTP security headers (X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Referrer-Policy, etc.).SessionLayer: Manages signed, encrypted cookie sessions (SignedCookieStore).csrf_layer(): Enforces Cross-Site Request Forgery (CSRF) protection on mutating requests (POST,PUT,DELETE), requiringcsrftokencookies andX-CSRFTokenheaders.
2. Favicon & Static File Serving
In src/urls.rs, djangors_admin::favicon_routes wraps the main application router to automatically handle favicon.ico requests:
#![allow(unused)]
fn main() {
mod views {
use djangors_core::{DjangorsError, PathParams, Request, Response, StatusCode};
pub async fn index(_: Request, _: PathParams) -> Result<Response, DjangorsError> { Ok(Response::html(StatusCode::OK, "")) }
pub async fn detail(_: Request, _: PathParams) -> Result<Response, DjangorsError> { Ok(Response::html(StatusCode::OK, "")) }
pub async fn results(_: Request, _: PathParams) -> Result<Response, DjangorsError> { Ok(Response::html(StatusCode::OK, "")) }
pub async fn vote(_: Request, _: PathParams) -> Result<Response, DjangorsError> { Ok(Response::html(StatusCode::OK, "")) }
pub async fn login_view(_: Request, _: PathParams) -> Result<Response, DjangorsError> { Ok(Response::html(StatusCode::OK, "")) }
pub async fn logout_view(_: Request, _: PathParams) -> Result<Response, DjangorsError> { Ok(Response::html(StatusCode::OK, "")) }
}
mod admin {
use djangors_admin::AdminSite;
pub fn admin_site() -> AdminSite { AdminSite::new() }
}
use djangors_core::Router;
pub fn urls() -> Router {
djangors_admin::favicon_routes(
Router::new()
.get("/", views::index)
.get("/{question_id:i64}/", views::detail)
.get("/{question_id:i64}/results/", views::results)
.post("/{question_id:i64}/vote/", views::vote)
.post("/accounts/login/", views::login_view)
.post("/accounts/logout/", views::logout_view)
.mount("/admin", self::admin::admin_site().urls()),
)
}
}
3. Collecting Static Assets for Production
Djangors provides dj collectstatic to discover static assets across source directories, generate cache-busting content hashes, and output them along with a manifest.json:
# Collect static files into the deployment output directory
dj collectstatic --source static --output staticfiles
What’s Real vs. What Django Has That Djangors Doesn’t Yet
Important
Key Architecture Differences from Django:
- Tower Middleware: Instead of string lists in
MIDDLEWARE = [...], middleware is constructed at compile-time using Rust’stower::ServiceBuilder.- Session Store:
SignedCookieStorestores cryptographically signed session state directly in browser cookies without requiring a database session table by default.- Static Manifests:
dj collectstaticproduces a production manifest JSON file containing hashed asset paths for high-performance static file serving.
Running and Verifying
- Verify static file collection:
mkdir -p static
echo "body { background: #f0f0f0; }" > static/style.css
dj collectstatic --source static --output staticfiles
- Inspect the generated manifest in
staticfiles/manifest.json.