Advanced Features | Django LiveView

Intersection Observer (Infinite Scroll)

Trigger functions when elements enter or exit the viewport:

ITEMS_PER_PAGE = 10

@liveview_handler("load_more")
def load_more(consumer, content):
    page = int(content["data"].get("page", 1))

    # Fetch items
    start = (page - 1) * ITEMS_PER_PAGE
    end = start + ITEMS_PER_PAGE
    items = Item.objects.all()[start:end]
    is_last_page = end >= Item.objects.count()

    # Append items to list
    send(consumer, {
        "target": "#items-list",
        "html": render_to_string("items_partial.html", {
            "items": items
        }),
        "append": True
    })

    # Update or remove intersection observer trigger
    if is_last_page:
        html = ""
    else:
        html = render_to_string("load_trigger.html", {
            "next_page": page + 1
        })

    send(consumer, {
        "target": "#load-more-trigger",
        "html": html
    })

HTML template:

<!-- load_trigger.html -->
<div
    data-liveview-intersect-appear="load_more"
    data-data-page="{{ next_page }}"
    data-liveview-intersect-threshold="200">
    <p>Loading more...</p>
</div>

Attributes:

  • data-liveview-intersect-appear="function_name" — Call when element appears

  • data-liveview-intersect-disappear="function_name" — Call when element disappears

  • data-liveview-intersect-threshold="200" — Trigger 200px before entering viewport (default: 0)

Auto-focus

Automatically focus elements after rendering:

<input
    type="text"
    name="title"
    value="{{ item.title }}"
    data-liveview-focus="true">

Init Functions

Execute functions when elements are first rendered:

<div
    data-liveview-init="init_counter"
    data-data-counter-id="1"
    data-data-initial-value="0">
    <span id="counter-1-value"></span>
</div>

Debounce

Reduce server calls by adding a delay before sending requests. Perfect for search inputs and real-time validation:

<input
    type="search"
    name="search"
    data-liveview-function="search_articles"
    data-liveview-debounce="500"
    data-action="input->page#run"
    placeholder="Search articles...">

The data-liveview-debounce="500" attribute waits 500ms after the user stops typing before sending the request. This dramatically reduces server load and provides a better user experience.

Example: Real-time search with debounce

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

@liveview_handler("search_articles")
def search_articles(consumer, content):
    query = content["form"]["search"]
    articles = Article.objects.filter(title__icontains=query)

    html = render_to_string("search_results.html", {
        "articles": articles
    })

    send(consumer, {
        "target": "#search-results",
        "html": html
    })

Without debounce, typing "python" would send 6 requests (one per letter). With data-liveview-debounce="500", it sends only 1 request after the user stops typing for 500ms.

Middleware System

Add middleware to run before handlers for authentication, logging, or rate limiting:

from liveview import liveview_registry, send

def auth_middleware(consumer, content, function_name):
    """Check if user is authenticated before running handler"""
    user = consumer.scope.get("user")

    if not user or not user.is_authenticated:
        send(consumer, {
            "target": "#error",
            "html": "<p>You must be logged in</p>"
        })
        return False  # Cancel handler execution

    return True  # Continue to handler

def logging_middleware(consumer, content, function_name):
    """Log all handler calls"""
    import logging
    logger = logging.getLogger(__name__)

    user = consumer.scope.get("user")
    logger.info(f"Handler '{function_name}' called by {user}")

    return True  # Continue to handler

# Register middleware
liveview_registry.add_middleware(auth_middleware)
liveview_registry.add_middleware(logging_middleware)