Skip to content
djust
Appearance
Mode

LiveView

The LiveView class is the core building block of djust. It combines a Django class-based view with a persistent WebSocket session that keeps state on the server.

Basic Structure

from djust import LiveView
from djust.decorators import event_handler


class MyView(LiveView):
    template_name = "myapp/my_view.html"

    def mount(self, request, **kwargs):
        """Initialize state. Called once on page load."""
        self.count = 0
        self.items = []

    def get_context_data(self, **kwargs):
        """Return template context. Called before every render."""
        return {"count": self.count, "items": self.items}

    @event_handler()
    def increment(self, **kwargs):
        """Handle a dj-click="increment" event."""
        self.count += 1

Lifecycle Hooks

mount(request, **kwargs)

Called once when the LiveView is first loaded (HTTP request). Use this to:

  • Initialize state variables
  • Read URL parameters from **kwargs
  • Fetch initial data from the database
def mount(self, request, **kwargs):
    item_id = kwargs.get("item_id")
    self.item = Item.objects.get(pk=item_id)
    self.editing = False

After mount(), every state change triggers a re-render automatically.

get_context_data(**kwargs)

Called before every render — both the initial HTTP render and every WebSocket update. Returns the template context dictionary.

Always call super().get_context_data(**kwargs) to include djust's required context:

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context.update({
        "items": self.items,
        "count": self.count,
    })
    return context

handle_params(params, url, **kwargs)

Called when URL parameters change via live_patch() navigation (without a full page reload):

def handle_params(self, params, url, **kwargs):
    self.page = int(params.get("page", 1))
    self._refresh()

handle_info(event, data, **kwargs)

Called when the server sends a message to this LiveView (e.g., from background tasks or PubSub):

def handle_info(self, event, data, **kwargs):
    if event == "new_message":
        self.messages.append(data["message"])

State Management

State lives on self. Any public attribute (self.count) is:

  • Included in the template context
  • Preserved across WebSocket events
  • Re-rendered when changed

Private attributes (prefixed with _) are excluded from serialization:

def mount(self, request, **kwargs):
    self._db_items = Item.objects.all()  # private — not serialized
    self.count = self._db_items.count()  # public — available in template

Inline Templates

For simple views, use template instead of template_name:

class HelloView(LiveView):
    template = "<h1>Hello {{ name }}!</h1>"

    def mount(self, request, **kwargs):
        self.name = "World"

URL Configuration

LiveViews use Django's standard as_view():

from django.urls import path
from myapp.views import MyView

urlpatterns = [
    path("items/<int:item_id>/", MyView.as_view(), name="my-view"),
]

Authentication

Use Django's built-in mixins:

from django.contrib.auth.mixins import LoginRequiredMixin
from djust import LiveView

class ProtectedView(LoginRequiredMixin, LiveView):
    template_name = "myapp/protected.html"
    login_url = "/login/"

Or use djust's permission decorator on individual handlers:

from djust.decorators import event_handler, permission_required

@event_handler()
@permission_required("myapp.can_delete")
def delete_item(self, item_id: int = 0, **kwargs):
    Item.objects.filter(pk=item_id).delete()

HTTP Fallback Mode

LiveViews work without WebSockets — they degrade gracefully to standard HTTP form submissions. This enables server-side rendering for environments that don't support WebSockets (some proxies, crawlers).

Next Steps