Django LiveView

Build real-time apps: write Python, not JavaScript

Django LiveView is a framework for creating real-time, interactive web applications entirely in Python, inspired by Phoenix LiveView and Laravel Livewire. It is built on top of Django Channels.

Build rich, dynamic user experiences with server-rendered HTML without writing a single line of JavaScript. Perfect for Django developers who want real-time features without the complexity of a separate frontend framework.

See it in action

Here's a complete example: a button that loads the latest blog article with a single click.

HTML:

<button
    data-liveview-function="load_latest_article"
    data-action="click->page#run">
    Load Latest Article
</button>

<div id="article-container"></div>

Python:

from liveview import liveview_handler, send
from django.template.loader import render_to_string

@liveview_handler("load_latest_article")
def load_latest_article(consumer, content):
    # Get the latest article from database
    article = Article.objects.latest('published_at')

    # Render with Django templates
    html = render_to_string('article.html', {
        'article': article
    })

    # Send to frontend
    send(consumer, {
        "target": "#article-container",
        "html": html
    })

Result (after clicking the button):

<button
    data-liveview-function="load_latest_article"
    data-action="click->page#run">
    Load Latest Article
</button>

<div id="article-container">
    <article>
        <h2>Understanding Django Channels</h2>
        <p class="meta">Published on Dec 15, 2024 by Jane Doe</p>
        <p>Django Channels extends Django to handle WebSockets,
           long-running connections, and background tasks...</p>
        <a href="/blog/understanding-django-channels/">Read more</a>
    </article>
</div>

That's it! No page reload, no API endpoints, no REST, no GraphQL, no frontend framework. The article appears instantly via WebSocket. Just Python and Django templates working together in real-time.

Key features

  • Create SPAs without APIs

    No REST or GraphQL needed.

  • Django templates

    Render the frontend without JavaScript frameworks.

  • Logic stays in Python

    No split between backend and frontend.

  • All of Django's tools

    ORM, forms, authentication, admin and more.

  • Async by default

    Built on Django Channels.

  • Zero learning curve

    If you know Python and Django, you're ready.

  • Real-time by design

    Every interaction happens over WebSockets.

  • Stateful connections

    Server-side state is kept for the whole session.

  • Batteries included

    Bundled JS assets and automatic reconnection with exponential backoff.

  • Browser history

    Back and forward restore the full page state automatically.

  • Broadcast support

    Multi-user real-time updates.

  • Middleware system

    Authentication and authorization.

Why Django LiveView?

Benchmarks show Django LiveView delivers the fastest response times among Django interactive frameworks:

Response Time Comparison

FrameworkAvg ResponseData TransferHTTP Requests
Django LiveView22.91 ms5.82 KB0
HTMX25.82 ms4.39 KB1
djust27.05 ms8.79 KB0
Reactor40.56 ms1.64 KB0
Unicorn50.58 ms6.33 KB1
SSR60.52 ms8.23 KB2

Django LiveView is approximately 11% faster than HTMX and 62% faster than traditional SSR through persistent WebSocket connectivity.

Technology Comparison

FeatureLiveViewSSRHTMXUnicorn
TransportWebSocketHTTPAJAXAJAX
Update TypeReal-timeFull reloadPartialReactive
Multi-userโœ… BroadcastโŒโŒโŒ
InfrastructureRedis + ChannelsDjango onlyDjango onlyDjango only

What makes it different?

The key difference is the connection model:

Django LiveView uses a persistent WebSocket connection that stays open between the client and server. This allows bidirectional, real-time communication with minimal latency. Think of it like a phone call: once connected, both sides can talk instantly.

HTMX sends a new HTTP request for each user interaction and updates only part of the page. It's like sending text messages: you send a message, wait for a response, then repeat. If you're migrating from HTMX, check out this migration guide.

Traditional SSR reloads the entire page with each interaction through a POST request followed by a redirect. It's like hanging up and calling back every time you want to say something.

sequenceDiagram
    accTitle: Initial page load over WebSocket
    accDescr: The browser sends the string "Open the Home Page" to the Django server, which replies with the full page HTML.
    autonumber
    participant B as ๐ŸŒ Browser
    participant S as ๐Ÿ–ฅ๏ธ Server ยท Django
    B->>S: String: "Open the Home Page"
    S-->>B: HTML: "<html><body><h1>โ€ฆ"

How does it work?

Let's illustrate with an example: displaying article number 2.

  1. A WebSocket connection (a channel) is established between the client and the server.

  2. JavaScript sends a message via WebSocket to the server (Django).

    sequenceDiagram
        accTitle: User action sent to the server
        accDescr: When the user clicks, JavaScript sends the action string "click->article#open:2" to the Django server over the WebSocket.
        participant B as ๐ŸŒ Browser
        participant S as ๐Ÿ–ฅ๏ธ Server ยท Django
        B->>S: String: "click->article#35;open:2"
    
  3. Django interprets the message and renders the HTML of the article through the template system and the database.

  4. Django sends the HTML to JavaScript via the channel and specifies which selector to embed it in.

    sequenceDiagram
        accTitle: Server response with the rendered HTML
        accDescr: The Django server replies with a JSON message containing the target selector "#main" and the rendered article HTML.
        participant B as ๐ŸŒ Browser
        participant S as ๐Ÿ–ฅ๏ธ Server ยท Django
        S-->>B: JSON: { selector: "#35;main", html: "<article>โ€ฆ" }
    
  5. JavaScript renders the received HTML in the indicated selector.

    flowchart TD
        accTitle: HTML placed into the target element
        accDescr: JavaScript inserts the received markup into the #main element, which now contains an article with a heading and a paragraph.
        M["div#main"] --> A["article"]
        A --> H["h1: Lorem ipsumโ€ฆ"]
        A --> P["p: โ€ฆ"]
    

The same process is repeated for each action: clicking a button, submitting a form, navigating, etc.