Skip to content
djust/docs
Appearance
Mode
djust.org →
Browse documentation

API Reference · 53 entries · self.

View API reference

The methods you call on self inside a LiveView to drive the page: stream content, track presence, accept uploads, manage forms, flash messages, push to the client, run background work, and navigate. Most become available once you mix in the matching capability (see the Mixins tab).

Streaming

10 entries

Push incremental updates into the page from a handler. The stream() family manages large collections with insert/delete/prune ops instead of full re-renders; stream_text() / stream_to() stream content (like LLM tokens) into a dj-stream target at ~60fps.

self.stream() Initialise a stream with a collection of items.
Signature
stream(name, items, dom_id=None, at=-1, reset=False, limit=None)
Returns
Stream

Sets up an efficient server-side stream; rows are emitted as insert ops instead of re-rendering the whole list, and cleared from server memory after render. at=-1 appends, at=0 prepends. Pairs with a dj-stream container. dom_id is a callable that derives each row's DOM id — if omitted, djust falls back to item.id, then item.pk, then id(item).

Python Usage
def mount(self, request, **kwargs):
    self.stream('messages', Message.objects.all()[:50])
self.stream_insert() Insert one item into a stream.
Signature
stream_insert(name, item, at=-1)
Returns
None

Adds a single item to an initialised stream. at=-1 appends (default), at=0 prepends. The item's id/pk becomes the DOM element id.

Python Usage
@event_handler()
def add_message(self, text: str = "", **kwargs):
    msg = Message.objects.create(content=text)
    self.stream_insert('messages', msg)
self.stream_delete() Remove an item from a stream by item or id.
Signature
stream_delete(name, item_or_id)
Returns
None

Deletes a row from an initialised stream. Pass the item object or its id; the DOM id is derived from the stream name and item id/pk.

Python Usage
@event_handler()
def delete_message(self, msg_id: int = 0, **kwargs):
    Message.objects.filter(pk=msg_id).delete()
    self.stream_delete('messages', msg_id)
self.stream_reset() Clear a stream, optionally repopulating it.
Signature
stream_reset(name, items=None)
Returns
None

Clears all of a stream's DOM children. If items is given, the stream is repopulated after clearing.

Python Usage
@event_handler()
def refresh(self, **kwargs):
    self.stream_reset('messages', items=Message.objects.all()[:50])
self.stream_prune() Cap the number of DOM elements in a stream.
Signature
stream_prune(name, limit, edge='top')
Returns
None

Trims a stream to at most limit elements. edge='top' removes from the start, 'bottom' from the end. Used for infinite scroll to keep the DOM bounded.

Python Usage
@event_handler()
def load_more(self, **kwargs):
    self.stream('messages', next_batch, at=-1)
    self.stream_prune('messages', limit=100, edge='top')
await self.stream_to() Send a streaming partial update to the client.
Signature
async stream_to(stream_name, target=None, html=None)
Returns
None

Batched (~60fps) streaming update over the WebSocket. If html is given it is sent directly, else the target is re-rendered from context. target defaults to [dj-stream='name'].

Python Usage
@event_handler()
async def stream_response(self, prompt: str = "", **kwargs):
    async for token in llm_stream(prompt):
        self.output += token
        await self.stream_to('output')
await self.stream_text() Stream raw text into a target element.
Signature
async stream_text(name, text, mode='append', target=None)
Returns
None

Appends (or replaces / prepends) text into the stream target. target defaults to [dj-stream='name']. The workhorse for LLM token streaming.

Python Usage
async def stream_response(self, **kwargs):
    async for chunk in fetch_stream():
        await self.stream_text('output', chunk)
await self.stream_start() Signal the start of a stream to the client.
Signature
async stream_start(name, target=None)
Returns
None

Fires a 'start' op — useful to show a spinner before tokens arrive. target defaults to [dj-stream='name'].

Python Usage
await self.stream_start('output')
self.streaming = True
await self.stream_done() Signal the end of a stream to the client.
Signature
async stream_done(name, target=None)
Returns
None

Fires a 'done' op — useful to clear the loading state once streaming finishes.

Python Usage
await self.stream_done('output')
self.streaming = False
await self.stream_error() Send an error state to a stream target.
Signature
async stream_error(name, error, target=None)
Returns
None

Fires an 'error' op while preserving partial content, so a failure is surfaced without wiping what was already streamed.

Python Usage
try:
    await self.stream_to('output')
except Exception as e:
    await self.stream_error('output', str(e))

Presence

6 entries

Track who is viewing and what they're doing. track_presence() registers the user with optional metadata; list_presences() and presence_count() read the group; broadcast_to_presence() messages everyone; get_cursors() (with LiveCursorMixin) powers collaborative cursors.

self.track_presence() Register this user in the presence group.
Signature
track_presence(meta=None)
Returns
None

Registers the user in the presence group identified by presence_key, with an optional meta dict (name, color, avatar…). No-op during HTTP prerender — only registers under WebSocket. Requires PresenceMixin.

Python Usage
def mount(self, request, **kwargs):
    self.track_presence(meta={'name': request.user.username})
self.untrack_presence() Remove this user from presence tracking.
Signature
untrack_presence()
Returns
None

Removes the user from the presence group. Called automatically on disconnect; call manually to leave a room without disconnecting.

Python Usage
@event_handler()
def leave_room(self, **kwargs):
    self.untrack_presence()
self.list_presences() List the active presences in the group.
Signature
list_presences()
Returns
list[dict]

Returns the active presence records (each a dict of the meta passed to track_presence). Empty if presence_key isn't set or the backend is unavailable.

Python Usage
def get_context_data(self, **kwargs):
    ctx = super().get_context_data(**kwargs)
    ctx['presences'] = self.list_presences()
    return ctx
self.presence_count() Count the active users in the group.
Signature
presence_count()
Returns
int

Imperative count of active presences. For templates prefer the auto-maintained {{ online_count }} attribute over calling this directly.

Python Usage
ctx['online'] = self.presence_count()
self.broadcast_to_presence() Broadcast an event to everyone in the group.
Signature
broadcast_to_presence(event, payload=None)
Returns
None

Sends a named event to all active sessions in the presence group; the payload dict is delivered as kwargs to handlers listening for that event.

Python Usage
@event_handler()
def announce(self, message: str = "", **kwargs):
    self.broadcast_to_presence('announcement', {'message': message})
self.get_cursors() Get live cursor positions (collaborative).
Signature
get_cursors()
Returns
dict

Returns user_id -> cursor data (x, y, timestamp, meta), with stale cursors filtered. Only available on LiveCursorMixin.

Python Usage
ctx['cursors'] = self.get_cursors()

Uploads

2 entries

Configure and consume file uploads server-side. Declare a slot with allow_upload() in mount() (it sets accept/multiple automatically), then read completed files with consume_uploaded_entries() in the handler that saves them.

self.allow_upload() Configure a named file-upload slot.
Signature
allow_upload(name, accept='', max_entries=1, max_file_size=10_000_000, resumable=False)
Returns
UploadConfig

Declares an upload slot referenced as dj-upload='name'. accept filters extensions/MIME types; the input's accept/multiple attrs are set automatically. resumable=True survives WS reconnects. Requires UploadMixin.

Python Usage
def mount(self, request, **kwargs):
    self.allow_upload('avatar', accept='.jpg,.png', max_file_size=5_000_000)
self.consume_uploaded_entries() Iterate completed uploads, cleaning up after.
Signature
consume_uploaded_entries(name)
Returns
generator[UploadEntry]

Yields UploadEntry objects (client_name, client_size, file, data) for completed uploads, cleaning up temp files after iteration. Call from the handler that saves the files.

Python Usage
@event_handler()
def save_avatar(self, **kwargs):
    for entry in self.consume_uploaded_entries('avatar'):
        default_storage.save(entry.client_name, entry.file)

Forms

5 entries

Work with a bound Django form inside a LiveView. Read live values and validation state with get_field_value() / get_field_errors() / has_field_errors(); reach the form object via form_instance; clear everything with reset_form(). Requires FormMixin.

self.reset_form() Reset a bound form to its initial state.
Signature
reset_form()
Returns
None

Clears form_data, field_errors and form_errors and resets validity. Requires FormMixin.

Python Usage
@event_handler()
def clear(self, **kwargs):
    self.reset_form()
self.form_instance The live Django form instance (re-hydrated).
Signature
form_instance (property)
Returns
forms.Form

Returns the bound Django form, re-creating it from serialized state when needed. Requires FormMixin.

Python Usage
field = self.form_instance.fields.get('email')
self.get_field_value() Get the current value of a form field.
Signature
get_field_value(field_name, default='')
Returns
Any

Returns form_data[field_name] or the default. Requires FormMixin.

Python Usage
email = self.get_field_value('email')
self.get_field_errors() Get the validation errors for a field.
Signature
get_field_errors(field_name)
Returns
list[str]

Returns the field's error messages, or an empty list. Requires FormMixin.

Python Usage
errors = self.get_field_errors('email')
self.has_field_errors() Check whether a field has errors.
Signature
has_field_errors(field_name)
Returns
bool

True if the field currently has validation errors. Requires FormMixin.

HTML Template
{% if has_field_errors('email') %}
  <span class="error">Invalid email</span>
{% endif %}

Flash & push

7 entries

Talk to the client outside the normal render. put_flash() queues a notification; page_title / page_meta update the document head via a side-channel; push_event() / push_commands() / trigger_submit() send events, JS command chains, and native form submits to the browser.

self.put_flash() Queue a transient flash message.
Signature
put_flash(level, message)
Returns
None

Queues a notification; level ('success','error','info'…) becomes the CSS class dj-flash-{level}. Flushed to the client after the response. Requires FlashMixin (auto-included).

Python Usage
@event_handler()
def save(self, **kwargs):
    self.put_flash('success', 'Saved!')
self.clear_flash() Clear queued flash messages.
Signature
clear_flash(level=None)
Returns
None

Clears all flash messages, or only those of a given level.

Python Usage
self.clear_flash('error')
self.push_event() Push a custom event to client JS hooks.
Signature
push_event(event, payload=None)
Returns
None

Dispatches to dj-hook handlers and as a CustomEvent on document; the payload dict becomes event.detail. Use for client-only side effects after a handler.

Python Usage
self.push_event('confetti', {'count': 50})
self.push_commands() Push a JS command chain to run on the client.
Signature
push_commands(chain)
Returns
None

Runs a djust.js.JSChain on the client for DOM automation (show/hide/add_class/focus/dispatch) with no client hook needed.

Python Usage
from djust.js import JS

self.push_commands(
    JS.add_class('highlight', to='#btn').focus('#btn')
)
self.trigger_submit() Trigger a native form POST on the client.
Signature
trigger_submit(selector)
Returns
None

After the handler, the client calls .submit() on the matching form (which must carry dj-trigger-action). Used for OAuth or payment handoffs that need a real navigation.

Python Usage
@event_handler()
def checkout(self, **kwargs):
    self.trigger_submit('#payment-form')
self.page_title Update the document title (no re-render).
Signature
page_title (property)
Returns
str

Assigning page_title queues a title update over a side-channel — no VDOM diff required. Requires PageMetadataMixin (auto-included).

Python Usage
self.page_title = f'Chat ({self.unread} unread)'
self.page_meta Update <meta> tags dynamically.
Signature
page_meta (property)
Returns
dict

Assigning a dict of name->content queues meta-tag updates (one command per key). Useful for OpenGraph/SEO on a reactive page.

Python Usage
self.page_meta = {'og:title': 'My Article'}

Async work

3 entries

Run work off the request cycle. start_async() schedules a callback to run after the current state flushes (re-rendering when it finishes); cancel_async() stops it; defer() runs a one-shot callback after render/patch completes — good for telemetry and cleanup.

self.start_async() Run a callback in the background after flushing.
Signature
start_async(callback, *args, name=None, **kwargs)
Returns
None

Schedules work to run after the current state flushes to the client, then re-renders on completion. Name tasks to run several concurrently. Requires AsyncWorkMixin (auto-included).

Python Usage
@event_handler()
def generate(self, **kwargs):
    self.generating = True
    self.start_async(self._do_generate, name='gen')

def _do_generate(self):
    self.output = expensive_call()
    self.generating = False
self.cancel_async() Cancel a background task by name.
Signature
cancel_async(name)
Returns
None

Cancels a scheduled task; if it's already running, its completion re-render is skipped.

Python Usage
@event_handler()
def cancel(self, **kwargs):
    self.cancel_async('gen')
    self.generating = False
self.defer() Run a callback once after render + patch.
Signature
defer(callback, *args, **kwargs)
Returns
None

Queues a sync callback to run after the render/patch cycle (no further re-render). Good for telemetry or cleanup that shouldn't block the response.

Python Usage
@event_handler()
def track(self, **kwargs):
    self.count += 1
    self.defer(self._record_metric)

Navigation

3 entries

Drive navigation from the server. handle_params() reacts to URL changes; live_patch() updates the URL and re-renders without remounting (state preserved); live_redirect() moves to a different LiveView over the same socket with no full page reload.

self.handle_params() React to URL parameter changes (override).
Signature
handle_params(params, uri)
Returns
None

Override to derive state from the URL. Called after mount, on live_patch, and on browser back/forward.

Python Usage
def handle_params(self, params, uri):
    self.category = params.get('category', 'all')
    self.page = int(params.get('page', 1))
self.live_patch() Update the URL without remounting.
Signature
live_patch(params=None, path=None, replace=False)
Returns
None

Updates the browser URL via pushState (or replaceState) and re-renders — but does not remount, so state is preserved. Pairs with handle_params().

Python Usage
@event_handler()
def filter(self, category='all', **kwargs):
    self.category = category
    self.live_patch(params={'category': category, 'page': 1})
self.live_redirect() Navigate to another LiveView over the socket.
Signature
live_redirect(path, params=None, replace=False)
Returns
None

Navigates to a different LiveView on the same WebSocket — no full page reload. The old view unmounts and the new one mounts.

Python Usage
@event_handler()
def open_detail(self, item_id=0, **kwargs):
    self.live_redirect(f'/items/{item_id}/')

Wizard

4 entries

Step through a multi-step form. next_step() / prev_step() / go_to_step() navigate with per-step validation; submit_wizard() re-validates every step before calling on_wizard_complete(). Requires WizardMixin.

self.go_to_step() Jump to a completed wizard step.
Signature
go_to_step(step_index=0)
Returns
None

Navigates to a previously-completed step for editing, skipping validation on the jump. Requires WizardMixin.

Python Usage
@event_handler()
def edit_step(self, step_index: int = 0, **kwargs):
    self.go_to_step(step_index=step_index)
self.next_step() Validate and advance to the next step.
Signature
next_step()
Returns
None

Validates the current step, marks it complete, and advances. Stops at the last step. Requires WizardMixin.

HTML Template
<button dj-click="next_step">Next</button>
self.prev_step() Go back one wizard step.
Signature
prev_step()
Returns
None

Returns to the previous step without validation. Stops at the first step. Requires WizardMixin.

HTML Template
<button dj-click="prev_step">Back</button>
self.submit_wizard() Validate all steps and finish the wizard.
Signature
submit_wizard()
Returns
None

Re-validates every step (guarding against tampering) and calls on_wizard_complete(step_data) when all pass. Requires WizardMixin.

Python Usage
def on_wizard_complete(self, step_data):
    Claim.objects.create(**step_data['personal'])

JS commands

13 entries

JS commands are djust's equivalent of Phoenix LiveView's JS module: build a chain of DOM operations in Python (from djust.js import JS), bind it to any event attribute (dj-click="{{ chain }}"), and it runs client-side with zero server round-trip — mix in .push() when you do want one. Every command accepts at most one targeting kwarg: to= (absolute selector), inner= (within the origin element), or closest= (walk up from the origin); with none, the command targets the element that fired the event. Chains are immutable and safe to share. Beyond the built-ins, JS.ext.<name>() invokes commands you register client-side with window.djust.commands.register() (djust 1.1+) — typos fail loud (built-ins raise AttributeError at mount; unknown custom commands show the DEBUG error overlay with a did-you-mean hint). To run a chain from a server handler instead of an event binding, see self.push_commands() under Flash & push.

JS.show() Unhide the target element (clears display:none and the hidden attribute).
Signature
JS.show(to=None, *, inner=None, closest=None, display=None, transition=None, time=None)
Returns
None

Starts (or continues) a chain that makes the target visible client-side. Optional display= sets an explicit display value; transition=/time= apply a CSS class for the duration. Dispatches a djust:show CustomEvent on each target.

Python Open a modal with zero latency
self.open_modal = JS.show("#modal").add_class("open", to="#overlay").focus("#modal-title")
HTML Bind it
<button dj-click="{{ open_modal }}">Open</button>
JS.hide() Set the target element's display to none.
Signature
JS.hide(to=None, *, inner=None, closest=None, transition=None, time=None)
Returns
None

The closest= targeting makes reusable close buttons: the same button works inside every modal with no per-instance IDs. Dispatches djust:hide on each target.

HTML One close button for every modal
<div class="modal">
    <button dj-click="{{ JS.hide(closest='.modal') }}">Close</button>
</div>
JS.toggle() Flip the target between hidden and shown.
Signature
JS.toggle(to=None, *, inner=None, closest=None, display=None)
Returns
None

Checks computed display (and the hidden attribute) and flips it — the one-liner dropdown.

HTML Dropdown without a server round-trip
<div>
    <button dj-click="{{ JS.toggle(inner='.menu') }}">Menu</button>
    <nav class="menu" style="display:none"></nav>
</div>
JS.add_class() Add one or more space-separated CSS classes to the target.
Signature
JS.add_class(names, *, to=None, inner=None, closest=None)
Returns
None

Pairs with JS.remove_class() for manual class control; for timed classes use JS.transition().

Python Highlight on click
self.mark = JS.add_class("selected ring-2", closest=".card")
JS.remove_class() Remove one or more space-separated CSS classes from the target.
Signature
JS.remove_class(names, *, to=None, inner=None, closest=None)
Returns
None

The inverse of JS.add_class(); chain both to move a class between elements in one click.

Python Swap active state
self.activate = JS.remove_class("active", to=".tab").add_class("active")
JS.transition() Apply CSS classes for N milliseconds, then remove them.
Signature
JS.transition(names, *, to=None, inner=None, closest=None, time=200)
Returns
None

The animation primitive: add the class, wait time= ms for the CSS animation, remove it again.

Python Flash feedback
self.saved = JS.transition("flash-green", time=400, to="#status")
JS.set_attr() Set an HTML attribute on the target element.
Signature
JS.set_attr(name, value, *, to=None, inner=None, closest=None)
Returns
None

Useful for ARIA state that should update at click-time latency, ahead of the server render.

Python ARIA state
self.expand = JS.set_attr("aria-expanded", "true").show(inner=".panel")
JS.remove_attr() Remove an HTML attribute from the target element.
Signature
JS.remove_attr(name, *, to=None, inner=None, closest=None)
Returns
None

The inverse of JS.set_attr() — e.g. drop disabled the instant the user acts.

Python Enable a button
self.unlock = JS.remove_attr("disabled", to="#submit")
JS.focus() Move keyboard focus to the target element.
Signature
JS.focus(to=None, *, inner=None, closest=None)
Returns
None

Focuses the first matched target; chain it after JS.show() so the revealed input is ready to type into.

Python Reveal and focus search
self.search = JS.show("#search").focus("#search-input")
JS.dispatch() Fire a CustomEvent on the target element.
Signature
JS.dispatch(event, *, to=None, inner=None, closest=None, detail=None, bubbles=True)
Returns
None

The bridge to any third-party code already listening for DOM events — pass a payload via detail=.

Python Notify a listener
self.notify = JS.dispatch("cart:updated", to="#cart", detail={"count": 3})
JS.push() Send a server event as part of a client-side chain.
Signature
JS.push(event, *, value=None, target=None, page_loading=False)
Returns
None

The escape hatch back to the server: rides the normal event pipeline (debouncing, rate limiting, WebSocket/HTTP fallback). Enables optimistic UI — do the instant DOM work client-side, then tell the server. page_loading=True drives the page loading bar while the event is in flight.

Python Optimistic UI: close instantly, then save
self.place_order = (JS.hide("#checkout-modal")
                      .push("submit_order", value={"cart_id": self.cart_id}))
JS.ext.* Invoke a user-registered custom command from a Python chain.
Signature
JS.ext.<name>(to=None, *, inner=None, closest=None, **params)
Returns
None

Opens the command set (djust 1.1+): any snake_case name under JS.ext serializes as a namespaced ext.<name> op and dispatches to the matching window.djust.commands.register() implementation — clipboard, scroll, confetti, or a wrapper around any third-party library action. Chainable with built-ins, same targeting kwargs, structurally collision-proof against future built-ins. Built-ins stay strict (JS.shwo raises AttributeError at mount); an unregistered custom command fails loud on first use (DEBUG error overlay with a did-you-mean hint).

Python Copy-to-clipboard with instant feedback
self.copy_link = (JS.ext.clipboard_copy(text=self.share_url)
                    .add_class("copied")
                    .transition("pulse", time=400))
HTML Bind it
<button dj-click="{{ copy_link }}">Copy link</button>
window.djust.commands.register() Register the client-side implementation of a custom JS command.
Signature
register(name, fn) // fn(targets, args, originEl)
Returns
None

The client half of JS.ext (djust 1.1+): register once in your own static JS — no build step, CSP-safe (no eval). The implementation receives the already-resolved target element list (same to/inner/closest rules as built-ins), the op args, and the origin element; a returned Promise is awaited before the next op in the chain runs. Registering a name that collides with a built-in throws immediately.

JavaScript Implementation (static/app.js)
window.djust.commands.register('clipboard_copy', (targets, args) => {
    navigator.clipboard.writeText(args.text);
});
JavaScript Async commands hold the chain
window.djust.commands.register('fade_out', (targets) =>
    Promise.all(targets.map(el =>
        el.animate({opacity: [1, 0]}, 250).finished))
);
// Python: JS.ext.fade_out(closest='.row').hide(closest='.row').push('dismiss')
// the fade COMPLETES before the hide and the server push run