Home Features Docs Blog Philosophy Examples FAQ Live Demo Hosting
API Reference

View API

All 40self. methods you call on self inside a LiveView.

These are 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

Append, replace, and stream into the DOM

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.
# self.stream()

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
def mount(self, request, **kwargs):
    self.stream('messages', Message.objects.all()[:50])
self.stream_insert() Insert one item into a stream.
# self.stream_insert()

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
@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.
# self.stream_delete()

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
@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.
# self.stream_reset()

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
@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.
# self.stream_prune()

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
@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.
# await self.stream_to()

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
@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.
# await self.stream_text()

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
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.
# await self.stream_start()

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
await self.stream_start('output')
self.streaming = True
await self.stream_done() Signal the end of a stream to the client.
# await self.stream_done()

Signature

async stream_done(name, target=None)

Returns

None

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

Python
await self.stream_done('output')
self.streaming = False
await self.stream_error() Send an error state to a stream target.
# await self.stream_error()

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
try:
    await self.stream_to('output')
except Exception as e:
    await self.stream_error('output', str(e))

Presence

Who's online + collaborative cursors

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.
# self.track_presence()

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
def mount(self, request, **kwargs):
    self.track_presence(meta={'name': request.user.username})
self.untrack_presence() Remove this user from presence tracking.
# self.untrack_presence()

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
@event_handler()
def leave_room(self, **kwargs):
    self.untrack_presence()
self.list_presences() List the active presences in the group.
# self.list_presences()

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
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.
# self.presence_count()

Signature

presence_count()

Returns

int

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

Python
ctx['online'] = self.presence_count()
self.broadcast_to_presence() Broadcast an event to everyone in the group.
# self.broadcast_to_presence()

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
@event_handler()
def announce(self, message: str = "", **kwargs):
    self.broadcast_to_presence('announcement', {'message': message})
self.get_cursors() Get live cursor positions (collaborative).
# self.get_cursors()

Signature

get_cursors()

Returns

dict

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

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

Uploads

Configure slots and consume files

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.
# self.allow_upload()

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
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.
# self.consume_uploaded_entries()

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
@event_handler()
def save_avatar(self, **kwargs):
    for entry in self.consume_uploaded_entries('avatar'):
        default_storage.save(entry.client_name, entry.file)

Forms

Bind, validate, and read form fields

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.
# self.reset_form()

Signature

reset_form()

Returns

None

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

Python
@event_handler()
def clear(self, **kwargs):
    self.reset_form()
self.form_instance The live Django form instance (re-hydrated).
# self.form_instance

Signature

form_instance (property)

Returns

forms.Form

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

Python
field = self.form_instance.fields.get('email')
self.get_field_value() Get the current value of a form field.
# self.get_field_value()

Signature

get_field_value(field_name, default='')

Returns

Any

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

Python
email = self.get_field_value('email')
self.get_field_errors() Get the validation errors for a field.
# self.get_field_errors()

Signature

get_field_errors(field_name)

Returns

list[str]

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

Python
errors = self.get_field_errors('email')
self.has_field_errors() Check whether a field has errors.
# self.has_field_errors()

Signature

has_field_errors(field_name)

Returns

bool

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

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

Flash & push

Notifications, page metadata, client pushes

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.
# self.put_flash()

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
@event_handler()
def save(self, **kwargs):
    self.put_flash('success', 'Saved!')
self.clear_flash() Clear queued flash messages.
# self.clear_flash()

Signature

clear_flash(level=None)

Returns

None

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

Python
self.clear_flash('error')
self.push_event() Push a custom event to client JS hooks.
# self.push_event()

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
self.push_event('confetti', {'count': 50})
self.push_commands() Push a JS command chain to run on the client.
# self.push_commands()

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
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.
# self.trigger_submit()

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
@event_handler()
def checkout(self, **kwargs):
    self.trigger_submit('#payment-form')
self.page_title Update the document title (no re-render).
# self.page_title

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
self.page_title = f'Chat ({self.unread} unread)'
self.page_meta Update <meta> tags dynamically.
# self.page_meta

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
self.page_meta = {'og:title': 'My Article'}

Async work

Run work off the request, then re-render

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.
# self.start_async()

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
@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.
# self.cancel_async()

Signature

cancel_async(name)

Returns

None

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

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

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
@event_handler()
def track(self, **kwargs):
    self.count += 1
    self.defer(self._record_metric)

Navigation

URL params, live patch, and redirect

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).
# self.handle_params()

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
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.
# self.live_patch()

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
@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.
# self.live_redirect()

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
@event_handler()
def open_detail(self, item_id=0, **kwargs):
    self.live_redirect(f'/items/{item_id}/')

Wizard

Step through a multi-step form

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.
# self.go_to_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
@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.
# self.next_step()

Signature

next_step()

Returns

None

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

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

Signature

prev_step()

Returns

None

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

HTML
<button dj-click="prev_step">Back</button>
self.submit_wizard() Validate all steps and finish the wizard.
# self.submit_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
def on_wizard_complete(self, step_data):
    Claim.objects.create(**step_data['personal'])