djust 0.4.0 — The Developer Experience Release
djust 0.4.0 is our biggest release since 0.3. While 0.3 brought Phoenix LiveView parity, 0.4 is about developer experience — making everyday tasks faster, safer, and more intuitive. 30+ new features, critical bug fixes, and a security hardening pass that eliminated every known vulnerability.
Highlights
1. Flash Messages
Phoenix-style ephemeral flash notifications, built in:
class OrderView(LiveView):
@event_handler
def place_order(self, **kwargs):
Order.objects.create(user=self.request.user)
self.put_flash("success", "Order placed!")
self.put_flash("info", "Confirmation email sent.")
Messages are flushed to the client after each response over WebSocket or SSE. The {% dj_flash %} template tag renders the container with auto-dismiss, ARIA roles, and configurable positioning. Works over both WebSocket and HTTP POST fallback. Read the Flash Messages guide →
2. Declarative HTML Attributes
0.4 adds a suite of HTML attributes that eliminate boilerplate JavaScript:
dj-debounce="300"/dj-throttle="150"— Rate-limit any event directly in HTMLdj-click-away="close_dropdown"— Fire events on outside clicksdj-shortcut="ctrl+k:open_search, escape:close_modal"— Declarative keyboard shortcuts with modifier supportdj-disable-with="Saving..."— Auto-disable submit buttons with loading textdj-lock— Prevent concurrent event handler executiondj-mounted="on_chart_ready"— Element lifecycle eventsdj-cloak— Prevent flash of unconnected contentdj-scroll-into-view— Auto-scroll elements after DOM updatesdj-window-keydown.escape="close"— Window/document-scoped events
Every attribute is declarative, server-driven, and works with the existing dj-value-* param system. See the Template Cheatsheet →
3. Form Recovery on Reconnect
When a WebSocket connection drops and reconnects, form state used to be lost. Now djust automatically recovers it:
<!-- Fields with dj-change/dj-input auto-recover -->
<input dj-change="update_name" value="{{ name }}">
<!-- Opt out specific fields -->
<input dj-change="update_token" dj-no-recover>
<!-- Custom recovery for complex state -->
<div dj-auto-recover="restore_editor_state">
<textarea id="editor">...</textarea>
</div>
Form values are compared against server-rendered defaults — only changed fields fire recovery events. Exponential backoff with jitter (AWS full-jitter strategy) prevents thundering herd on server restart. Read the Reconnection guide →
4. Scaffolding Generator
Generate a complete CRUD LiveView in one command:
python manage.py djust_gen_live blog Post title:string body:text published:boolean
# Creates:
# blog/views.py — LiveView with list/create/update/delete handlers
# blog/urls.py — live_session() routing
# blog/templates/ — HTML template with dj-* directives
# blog/tests.py — Test suite
Supports all Django field types including FK relationships, --dry-run preview, and --force overwrite. Read the Scaffolding guide →
5. Dynamic Page Metadata
Update document.title and <meta> tags from any event handler — no VDOM diff needed:
class ArticleView(LiveView):
@event_handler
def load_article(self, slug: str = "", **kwargs):
self.article = Article.objects.get(slug=slug)
self.page_title = self.article.title
self.page_meta = {
"description": self.article.excerpt,
"og:title": self.article.title,
"og:image": self.article.image_url,
}
Supports og: and twitter: meta tags with correct property attribute. Uses side-channel WebSocket messages for instant updates. Read the Document Metadata guide →
6. on_mount Hooks
Cross-cutting mount logic without modifying every view:
from djust.decorators import on_mount
@on_mount
def require_verified_email(view, request):
if not request.user.email_verified:
return "/verify-email" # Redirect halts mount
@on_mount
def track_page_view(view, request):
Analytics.track(request.user, request.path)
class DashboardView(LiveView):
on_mount = [require_verified_email, track_page_view]
Hooks run after auth checks, before mount(). Return a URL string to redirect. Inherited via MRO with deduplication. Phoenix on_mount v0.17+ parity. Read the on_mount Hooks guide →
7. Debug Tooling
Three new tools for development:
manage.py djust_doctor— One-command diagnostic that checks Rust extension, Python/Django versions, Channels, Redis, templates, static files, routing, and ASGI server. Supports--jsonoutput for CI.- Warning interceptor — Debug panel captures
[LiveView]console warnings and surfaces them as a badge. - Latency simulator — Test loading states with simulated network delay (50–500ms presets, custom values, jitter control).
Read the Developer Tools guide →
8. Security Hardening
We ran the full CodeQL and Dependabot security suite and fixed everything:
- 25 CodeQL alerts resolved — UNSAFE_KEYS guards on VDOM patches reject
__proto__/constructor/prototype,Object.defineProperty()for debug panel state cloning, format strings for all logging - 19 Dependabot alerts resolved — Django ≥4.2.29, urllib3 ≥2.6.3, setuptools ≥78.1.1, and more
- WhiteNoise removed —
ASGIStaticFilesHandlerhandles static files at the ASGI layer, making WhiteNoise redundant
Bug Fixes
Critical reliability fixes that make 0.4 production-solid:
- Tick/event version mismatch — Server ticks could collide with user events, silently dropping patches. Now serialized with
asyncio.Lockand client-side buffering. - Focus lost during VDOM patches — Cursor position, selection range, and scroll position are now saved and restored around patch cycles.
- {% if %} blocks breaking VDOM — Comment node placeholders are now included in child index resolution.
- Template engine — Custom tag args properly serialize lists/objects, apply Django filters, and handle
True/False/Noneliterals.
Also Since 0.3.0 (0.3.1–0.3.8)
If you're upgrading from 0.3.0, here's what you missed in 0.3.1–0.3.8:
3.8x Rendering Speedup (0.3.1)
Replaced dir(self) iteration (~300 inherited Django View attributes) with targeted __dict__ + MRO walk. Combined with dj-update="ignore" optimization in the Rust VDOM diff engine, event roundtrip dropped from ~160ms to ~42ms on large pages.
SSE Fallback Transport (0.3.2)
djust now automatically falls back to Server-Sent Events when WebSocket is unavailable (corporate proxies, enterprise firewalls). EventSource for server→client push, HTTP POST for client→server events. Transport negotiation is automatic.
Background Work (0.3.2)
The @background decorator and start_async() enable long-running operations (AI generation, API calls) without blocking the UI. Loading states persist through background work via the async_pending flag. Named tasks support cancellation via cancel_async(name). Read the Loading States guide →
TypeScript & Python Type Stubs (0.3.2)
Full TypeScript definitions (djust.d.ts) for the client-side API and PEP 561 compliant type stubs (_rust.pyi) for the Rust extension. IDE autocomplete and mypy type checking now work out of the box.
6 New Rust Template Tags (0.3.4)
{% widthratio %}, {% firstof %}, {% templatetag %}, {% spaceless %}, {% cycle %}, and {% now %} — all 57 Django built-in template filters are now supported. CSS Frameworks guide →
djust-deploy CLI (0.3.5)
Deploy to djustlive.com from the command line: djust-deploy login, djust-deploy deploy <project>, djust-deploy status. Read the djust-deploy guide →
FormMixin Production-Ready (0.3.7)
Six fixes that unblocked FormMixin with ModelForm over WebSocket: proper @event_handler decorators on submit_form()/validate_field(), FK serialization, form data re-hydration after WS session restore, and auto-populated form_choices. Read the Forms guide →
Codebase Cleanup (0.3.7)
Seven DRY refactors extracted shared patterns into reusable helpers: reinitAfterDOMUpdate(), addEventContext(), isWSConnected(), clearOptimisticPending(), get_djust_config(), BackendRegistry, and is_model_list().
Reliability Fixes (0.3.6–0.3.8)
- Multi-tab VDOM cache collision — Each tab now gets its own VDOM baseline keyed by URL
- Canvas elements cleared during morph —
width/heightpreserved for Chart.js compatibility dj-hookelements not re-initialized —updateHooks()now called in all DOM replacement paths (Hooks guide)- Checkbox/radio/select state sync — VDOM patches now sync DOM properties alongside HTML attributes
{% load %}tags preserved — Custom tag libraries survive Rust template inheritance- Quoted tag arguments with spaces —
name="My App"no longer split into separate tokens - Prefetch set cleared on SPA navigation — Links are properly prefetched after
live_redirect dj-patchon selects/inputs — Now uses WebSocketurl_changeinstead of full page reload
Breaking: model.id returns native type (0.3.6)
model.id previously returned a string; it now returns the native Python type (int, UUID, etc.). If your templates compare model.id against string literals, update them to use the native type.
Breaking Changes
requires-pythonbumped from≥3.8to≥3.9(Python 3.8 is EOL)- Django minimum bumped to
≥4.2.29for security fixes whitenoiseremoved from dependencies — useASGIStaticFilesHandlerinstead
Upgrading
pip install djust==0.4.0
New to djust? Start with the Getting Started guide. For the full changelog, see the CHANGELOG.
Related Posts
djust 0.3.0 — "Phoenix Rising" 🔥
The biggest djust release yet with 20+ major features. Authentication, server-push, multi-tenancy, PWA support, AI tooling, automatic change tracking, CSS framework support, and security hardening make 0.3 production-ready.
djust 0.2.2: The Debug Panel Gets Real
djust 0.2.2 transforms the debug panel from a static inspector into a live development companion. Event filtering, replay, network inspection, VDOM patch tracing, and live state updates via WebSocket — all wired up and working out of the box.
djust 0.2.1: WebSocket Security Hardening with Three Layers of Defense
djust 0.2.1 locks down WebSocket event dispatch with an event name guard, @event_handler decorator allowlist, server-side rate limiting, and per-IP connection tracking. A security-focused release with zero new features to break.