Skip to main content

Phoenix LiveView-style reactive components for Django with Rust-powered performance. Real-time UI updates over WebSocket, no JavaScript build step required.

Project description

djust

Reactive server-side rendering for Django, powered by Rust

djust brings Phoenix LiveView-style reactive components to Django. You write server-side Python; the client updates automatically over a WebSocket. There is no JavaScript to write, no bundler, and no build step in your project.

djust.org · Documentation · Quick Start · Examples

PyPI version CI MIT License Python 3.10+ Django 4.2+ PyPI Downloads

Features

  • Fast — Rust-powered template engine and virtual DOM diffing (10–100x faster than plain Django rendering; see Performance)
  • Reactive components — Phoenix LiveView-style server-side reactivity
  • Django compatible — works with existing Django templates and components
  • No build step — ~55 KB gzipped client JavaScript, no bundling required
  • WebSocket updates — real-time DOM patches over WebSocket, with HTTP fallback
  • Minimal payloads — diffing sends only what changed
  • Rust core — performance-critical paths (templates, VDOM, parsing) are written in Rust
  • Debug panel — interactive debugging with event history and VDOM inspection
  • Lazy hydration — defer WebSocket connections for below-the-fold content to reduce memory
  • TurboNav compatible — works with Turbo-style client-side navigation
  • PWA support — offline-first Progressive Web Apps with automatic sync
  • Multi-tenant — tenant isolation for SaaS architectures
  • Auth — view-level and handler-level authorization via Django permissions

Quick Example

from djust import LiveView, event_handler

class CounterView(LiveView):
    template_string = """
    <div>
        <h1>Count: {{ count }}</h1>
        <button dj-click="increment">+</button>
        <button dj-click="decrement">-</button>
    </div>
    """

    def mount(self, request, **kwargs):
        self.count = 0

    @event_handler
    def increment(self):
        self.count += 1  # Automatically updates client

    @event_handler
    def decrement(self):
        self.count -= 1

No JavaScript needed. State changes trigger minimal DOM updates automatically.

How Reactivity Works

djust uses a Rust-powered virtual DOM (VDOM) to diff server-rendered HTML and send only the changed patches over WebSocket. A few core attributes make everything click.

Template Anatomy

{% load djust_tags %}
<!DOCTYPE html>
<html>
<head>
    {% djust_scripts %}              {# Loads the client runtime #}
</head>
<body dj-view="{{ dj_view_id }}">   {# Identifies the WebSocket session #}
    <div dj-root>                    {# Reactive boundary — only this is diffed #}
        <h1>Count: {{ count }}</h1>
        <button dj-click="increment">+</button>
    </div>
    {# Static content outside dj-root is never touched by VDOM patching #}
</body>
</html>
Attribute Where Purpose
{% djust_scripts %} <head> Injects client JavaScript
dj-view="{{ dj_view_id }}" <body> Connects page to WebSocket session
dj-root Inner <div> Marks the reactive region; only HTML inside is diffed and patched

Stable List Identity

For lists that can reorder or have items inserted/deleted, add data-key or dj-key on each item. djust uses this to emit MoveChild patches instead of remove-then-insert pairs, preserving DOM state (focus, scroll position, animations):

{% for item in items %}
<div data-key="{{ item.id }}">
    {{ item.name }}
    <button dj-click="delete" data-item-id="{{ item.id }}">Delete</button>
</div>
{% endfor %}

Without a key, djust diffs by position — correct, but it produces more DOM mutations for reorders.

Common Pitfall: One-Sided {% if %} in Class Attributes

Using {% if %} without {% else %} inside an HTML attribute value can cause VDOM patching misalignment, because of djust's branch-aware div-depth counting:

{# WRONG: one-sided if inside class attribute #}
<div class="card {% if active %}active{% endif %}">

{# CORRECT: use full if/else #}
<div class="card {% if active %}active{% else %}{% endif %}">

{# ALSO CORRECT: move conditional outside the tag #}
{% if active %}
<div class="card active">
{% else %}
<div class="card">
{% endif %}
    ...
</div>

This applies only to attribute values — {% if %} blocks in element content work fine.

See the VDOM Architecture guide and Template Cheat Sheet for full details.

Getting Started

A complete walkthrough from zero to a working reactive counter in five steps.

Step 1 — Install

pip install djust django-channels

Step 2 — Add to INSTALLED_APPS and configure settings

In myproject/settings.py:

INSTALLED_APPS = [
    # ... your existing apps ...
    'channels',   # WebSocket support
    'djust',
]

ASGI_APPLICATION = 'myproject.asgi.application'

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels.layers.InMemoryChannelLayer',
    }
}

Step 3 — Configure asgi.py

Replace myproject/asgi.py with:

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from djust.websocket import LiveViewConsumer
from django.urls import path

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path('ws/live/', LiveViewConsumer.as_asgi()),
        ])
    ),
})

Step 4 — Add the URL route

In myproject/urls.py:

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

urlpatterns = [
    path('counter/', CounterView.as_view(), name='counter'),
]

Step 5 — Write the view and template

myapp/views.py:

from djust import LiveView, event_handler

class CounterView(LiveView):
    template_name = 'counter.html'

    def mount(self, request, **kwargs):
        self.count = 0

    @event_handler
    def increment(self):
        self.count += 1

    @event_handler
    def decrement(self):
        self.count -= 1

myapp/templates/counter.html:

{% load djust_tags %}
<!DOCTYPE html>
<html>
<head>
    <title>Counter</title>
    {% djust_scripts %}
</head>
<body dj-view="{{ dj_view_id }}">
    <div dj-root>
        <h1>Count: {{ count }}</h1>
        <button dj-click="increment">+</button>
        <button dj-click="decrement">-</button>
    </div>
</body>
</html>

Run with uvicorn myproject.asgi:application --reload and open /counter/. Clicking the buttons updates the count without a page reload — no JavaScript written, no build step.

Next steps:


Performance

Benchmarked on an M1 MacBook Pro (2021):

Operation Django djust Speedup
Template rendering (100 items) 2.5 ms 0.15 ms 16.7x
Large list (10k items) 450 ms 12 ms 37.5x
Virtual DOM diff N/A 0.08 ms sub-ms
Round-trip update 50 ms 5 ms 10x

Run the benchmarks yourself:

cd benchmarks
python benchmark.py

Installation

Prerequisites

  • Python 3.10+
  • Django 4.2+
  • Rust 1.70+ (only required when building from source)

Install from PyPI

pip install djust

Build from Source

Using Make (recommended for development)

# Clone the repository
git clone https://github.com/djust-org/djust.git
cd djust

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install everything and build
make install

# Start the development server
make start

# See all available commands
make help

Common Make commands:

  • make start — start development server with hot reload
  • make stop — stop the development server
  • make status — check if the server is running
  • make test — run all tests
  • make clean — clean build artifacts
  • make help — show all available commands

Using uv

# Clone the repository
git clone https://github.com/djust-org/djust.git
cd djust

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install uv (if needed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create virtual environment and install dependencies
uv venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Install maturin and build
uv pip install maturin
maturin develop --release

Using pip

# Clone the repository
git clone https://github.com/djust-org/djust.git
cd djust

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install maturin
pip install maturin

# Build and install
maturin develop --release

# Or build a wheel
maturin build --release
pip install target/wheels/djust-*.whl

Documentation

The full documentation lives at docs.djust.org. The sections below cover the core API; see Getting Started above for first-time setup.

Creating LiveViews

Class-Based LiveView

from djust import LiveView, event_handler

class TodoListView(LiveView):
    template_name = 'todos.html'  # Or use template_string

    def mount(self, request, **kwargs):
        """Called when view is first loaded"""
        self.todos = []

    @event_handler
    def add_todo(self, text):
        """Event handler — called from client"""
        self.todos.append({'text': text, 'done': False})

    @event_handler
    def toggle_todo(self, index):
        self.todos[index]['done'] = not self.todos[index]['done']

Function-Based LiveView

from djust import live_view

@live_view(template_name='counter.html')
def counter_view(request):
    count = 0

    def increment():
        nonlocal count
        count += 1

    return locals()  # Returns all local variables as context

Template Syntax

djust supports Django template syntax with event binding:

<!-- Variables -->
<h1>{{ title }}</h1>

<!-- Filters (all 57 Django built-in filters supported) -->
<p>{{ text|upper }}</p>
<p>{{ description|truncatewords:20 }}</p>
<a href="?q={{ query|urlencode }}">Search</a>
{{ body|urlize }}  {# No |safe needed — djust auto-marks urlize output as safe (see note below) #}

<!-- Control flow -->
{% if show %}
    <div>Visible</div>
{% endif %}

{% if count > 10 %}
    <div>Many items!</div>
{% endif %}

{% for item in items %}
    <li>{{ item }}</li>
{% endfor %}

<!-- URL resolution -->
<a href="{% url 'myapp:detail' pk=item.id %}">View</a>

<!-- Template includes -->
{% include "partials/header.html" %}

<!-- Event binding -->
<button dj-click="increment">Click me</button>
<input dj-input="on_search" type="text" />
<form dj-submit="submit_form">
    <input name="email" />
    <button type="submit">Submit</button>
</form>

Django migration note: In standard Django, urlize requires |safe to render its HTML output. djust's Rust template engine automatically marks urlize, urlizetrunc, and unordered_list as safe (via safe_output_filters in the renderer), because these filters handle their own HTML escaping internally. Adding |safe after them is unnecessary.

Supported Events

  • dj-click — click events
  • dj-input — input events (passes value)
  • dj-change — change events (passes value)
  • dj-submit — form submission (passes form data as a dict)

Reusable Components

djust includes a component system with automatic state management and stable component IDs.

Basic Component Example

from djust.components import AlertComponent

class MyView(LiveView):
    def mount(self, request):
        # Components get automatic IDs based on attribute names
        self.alert_success = AlertComponent(
            message="Operation successful!",
            type="success",
            dismissible=True
        )
        # component_id automatically becomes "alert_success"

Component ID Management

Components automatically receive a stable component_id based on their attribute name in your view, which eliminates manual ID management:

# When you write:
self.alert_success = AlertComponent(message="Success!")

# The framework automatically:
# 1. Sets component.component_id = "alert_success"
# 2. Persists this ID across renders and events
# 3. Uses it in HTML: data-component-id="alert_success"
# 4. Routes events back to the correct component

Why it works:

  • The attribute name (alert_success) is already unique within your view
  • It's stable across re-renders and WebSocket reconnections
  • Event handlers can reference components by their attribute names
  • No manual ID strings to keep in sync

Event routing example:

class MyView(LiveView):
    def mount(self, request):
        self.alert_warning = AlertComponent(
            message="Warning message",
            dismissible=True
        )

    @event_handler
    def dismiss(self, component_id: str = None):
        """Handle dismissal — automatically routes to correct component"""
        if component_id and hasattr(self, component_id):
            component = getattr(self, component_id)
            if hasattr(component, 'dismiss'):
                component.dismiss()  # component_id="alert_warning"

When the dismiss button is clicked, the client sends component_id="alert_warning", and the handler uses getattr(self, "alert_warning") to find the component.

Creating Custom Components

from djust import LiveComponent, event_handler
from djust.components import register_component

class ButtonComponent(LiveComponent):
    template = '<button dj-click="on_click" data-component-id="{{ component_id }}">{{ label }}</button>'

    def mount(self, **kwargs):
        self.label = kwargs.get("label", "Click")
        self.clicks = 0

    @event_handler()
    def on_click(self, **kwargs):
        self.clicks += 1
        self.trigger_update()

    def get_context_data(self):
        return {"label": self.label, "clicks": self.clicks}

# register_component accepts LiveComponent subclasses (stateful, event-driven)
register_component('my-button', ButtonComponent)

Decorators

from djust import LiveView, event_handler, reactive

class MyView(LiveView):
    @event_handler
    def handle_click(self):
        """Marks method as event handler"""
        pass

    @reactive
    def count(self):
        """Reactive property — auto-triggers updates"""
        return self._count

    @count.setter
    def count(self, value):
        self._count = value

Configuration

Configure djust in your Django settings.py:

LIVEVIEW_CONFIG = {
    # Transport mode
    'use_websocket': True,  # Set to False for HTTP-only mode (no WebSocket dependency)

    # Debug settings
    'debug_vdom': False,  # Enable detailed VDOM patch logging (for troubleshooting)

    # Serialization (issue #292)
    'strict_serialization': False,  # Raise TypeError for non-serializable state values (recommended in development)

    # CSS Framework
    'css_framework': 'bootstrap5',  # Options: 'bootstrap5', 'tailwind', None
}

Common configuration options:

Option Default Description
use_websocket True Use WebSocket transport (requires Django Channels)
debug_vdom False Enable detailed VDOM debugging logs
strict_serialization False Raise TypeError for non-serializable state (recommended in dev)
css_framework 'bootstrap5' CSS framework for components

CSS framework setup. For Tailwind CSS, use the one-command setup:

python manage.py djust_setup_css tailwind

This auto-detects template directories, creates config files, and builds your CSS. For production:

python manage.py djust_setup_css tailwind --minify

See the CSS Framework Guide for detailed setup instructions, Bootstrap configuration, and CI/CD integration.

Debug mode. When troubleshooting VDOM issues, enable debug logging:

# In settings.py
LIVEVIEW_CONFIG = {
    'debug_vdom': True,
}

# Or programmatically
from djust.config import config
config.set('debug_vdom', True)

This logs:

  • Server-side: patch generation details (stderr)
  • Client-side: patch application and DOM traversal (browser console)

State Management

djust provides Python-only state management decorators that remove the need for manual JavaScript.

Quick Start

Build a debounced search in eight lines of Python (no JavaScript):

from djust import LiveView
from djust.decorators import debounce

class ProductSearchView(LiveView):
    template_string = """
    <input dj-input="search" placeholder="Search products..." />
    <div>{% for p in results %}<div>{{ p.name }}</div>{% endfor %}</div>
    """

    def mount(self, request):
        self.results = []

    @debounce(wait=0.5)  # Wait 500ms after typing stops
    def search(self, query: str = "", **kwargs):
        self.results = Product.objects.filter(name__icontains=query)[:10]

The server only queries after you stop typing. Add @optimistic for instant UI updates, or @cache(ttl=300) to cache responses for five minutes.

See the State Management Quick Start.

Available Decorators

Decorator Use When Example
@debounce(wait) User is typing Search, autosave
@throttle(interval) Rapid events Scroll, resize
@optimistic Instant feedback Counter, toggle
@cache(ttl, key_params) Repeated queries Autocomplete
@client_state(keys) Multi-component Dashboard filters
@background Long operations AI generation, file processing
DraftModeMixin Auto-save forms Contact form

Quick decision guide:

  • Typing in an input? → @debounce(0.5)
  • Scrolling/resizing? → @throttle(0.1)
  • Need an instant UI update? → @optimistic
  • Same query multiple times? → @cache(ttl)
  • Multiple components? → @client_state([keys])
  • Long-running work? → @background or self.start_async(callback)
  • Auto-save forms? → DraftModeMixin

More documentation:

Navigation Patterns

djust provides three navigation mechanisms for building multi-view applications without full page reloads:

When to Use What

Scenario Use Why
Filter/sort/paginate within same view dj-patch / live_patch() No remount, URL stays bookmarkable
Navigate to a different LiveView dj-navigate / live_redirect() Same WebSocket, no page reload
Link to non-LiveView page Standard <a href> Full page load needed

Quick Decision Tree

Is this a direct user click on a link?
├─ Yes → Is it the same view (filter/sort)?
│   ├─ Yes → Use dj-patch
│   └─ No → Use dj-navigate
│
└─ No → Is navigation conditional on server logic?
    ├─ Yes → Use live_redirect() in @event_handler
    │   Examples: form validation, auth checks, async operations
    └─ No → You probably need dj-navigate (see anti-pattern below)

Anti-Pattern: Don't Use dj-click for Navigation

This is the most common mistake when building multi-view djust apps. Using dj-click to trigger a handler that immediately calls live_redirect() creates an unnecessary round-trip.

Wrong — using dj-click to trigger a handler that calls live_redirect():

# Anti-pattern: handler does nothing but navigate
@event_handler()
def go_to_item(self, item_id, **kwargs):
    self.live_redirect(f"/items/{item_id}/")  # Wasteful round-trip
<!-- Wrong: forces a WebSocket round-trip just to navigate -->
<button dj-click="go_to_item" dj-value-item_id="{{ item.id }}">View</button>

What actually happens:

  1. User clicks button → client sends WebSocket message (50–100ms)
  2. Server receives message, processes handler (10–50ms)
  3. Server responds with live_redirect command (50–100ms)
  4. Client finally navigates to the new view

Total: 110–250ms, plus handler processing time.

Right — using dj-navigate directly:

<!-- Right: client navigates immediately, no server round-trip -->
<a dj-navigate="/items/{{ item.id }}/">View Item</a>

What happens:

  1. User clicks link → client navigates directly

Total: ~10ms (just DOM updates).

Why it matters:

  • Performance: 10–20x faster navigation
  • Network efficiency: saves WebSocket bandwidth
  • User experience: instant response, no loading indicators needed
  • Simplicity: less code, fewer moving parts

When to Use live_redirect() in Handlers

Use handlers for navigation only when navigation depends on server-side logic or validation.

Conditional navigation after form validation:

@event_handler()
def submit_form(self, **kwargs):
    if self.form.is_valid():
        self.form.save()
        self.live_redirect("/success/")  # OK: conditional on validation
    else:
        # Stay on form to show errors
        pass

Navigation based on auth/permissions:

@event_handler()
def view_sensitive_data(self, **kwargs):
    if not self.request.user.has_perm('app.view_sensitive'):
        self.live_redirect("/access-denied/")  # OK: auth check required
        return
    self.show_sensitive = True

Navigation after async operations:

@event_handler()
async def create_and_view_item(self, name, **kwargs):
    item = await Item.objects.acreate(name=name, owner=self.request.user)
    self.live_redirect(f"/items/{item.id}/")  # OK: navigate to newly created item

Multi-step wizard logic:

@event_handler()
def next_step(self, **kwargs):
    if self.current_step == "payment" and not self.payment_valid:
        # Stay on payment step if invalid
        return
    self.current_step = self.get_next_step()
    self.live_patch(params={"step": self.current_step})  # OK: conditional flow

The common theme: the handler does meaningful work before navigating. If your handler only calls live_redirect(), use dj-navigate instead.

Quick Example: Multi-View App

from djust import LiveView
from djust.mixins.navigation import NavigationMixin
from djust.decorators import event_handler

class ProductListView(NavigationMixin, LiveView):
    template_string = """
    <!-- Filter within same view: use dj-patch -->
    <a dj-patch="?category=electronics">Electronics</a>
    <a dj-patch="?category=books">Books</a>

    <div>
        {% for product in products %}
            <!-- Navigate to different view: use dj-navigate -->
            <a dj-navigate="/products/{{ product.id }}/">{{ product.name }}</a>
        {% endfor %}
    </div>
    """

    def mount(self, request, **kwargs):
        self.category = "all"
        self.products = []

    def handle_params(self, params, uri):
        """Called when URL changes via dj-patch or browser back/forward"""
        self.category = params.get("category", "all")
        self.products = Product.objects.filter(category=self.category)

See the Navigation Guide for the complete API reference (live_patch(), live_redirect(), handle_params()).

Developer Tooling

Debug Panel

Interactive debugging tool for LiveView development (DEBUG mode only):

# In settings.py
DEBUG = True  # Debug panel automatically enabled

Open it with Ctrl+Shift+D (Windows/Linux) or Cmd+Shift+D (Mac), or click the floating debug button.

Features:

  • Event handlers — discover all handlers with parameters, types, and descriptions
  • Event history — real-time log with timing metrics (e.g., search • 45.2ms)
  • VDOM patches — monitor DOM updates with sub-millisecond precision
  • Variables — inspect current view state

See the Debug Panel Guide and Event Handler Best Practices.

Event Handlers

Always use the @event_handler decorator for auto-discovery and validation:

from djust.decorators import event_handler

@event_handler()
def search(self, value: str = "", **kwargs):
    """Search handler — description shown in debug panel"""
    self.search_query = value

Parameter convention: use value for form inputs (dj-input, dj-change events):

# Correct — matches what form events send
@event_handler()
def search(self, value: str = "", **kwargs):
    self.search_query = value

# Wrong — won't receive input value
@event_handler()
def search(self, query: str = "", **kwargs):
    self.search_query = query  # Always "" (default)

Architecture

┌─────────────────────────────────────────────┐
│  Browser                                    │
│  ├── client.js (~55 KB gz) — events & DOM  │
│  └── WebSocket connection                   │
└─────────────────────────────────────────────┘
           ↕ WebSocket (Binary/JSON)
┌─────────────────────────────────────────────┐
│  Django + Channels (Python)                 │
│  ├── LiveView classes                       │
│  ├── Event handlers                         │
│  └── State management                       │
└─────────────────────────────────────────────┘
           ↕ Python/Rust FFI (PyO3)
┌─────────────────────────────────────────────┐
│  Rust core (native speed)                   │
│  ├── Template engine (<1ms)                │
│  ├── Virtual DOM diffing (<100μs)          │
│  ├── HTML parser                            │
│  └── Binary serialization (MessagePack)    │
└─────────────────────────────────────────────┘

Examples

See the examples/demo_project directory for complete working examples:

  • Counter — simple reactive counter
  • Todo List — CRUD operations with lists
  • Chat — real-time messaging

Run the demo:

cd examples/demo_project
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver

Visit http://localhost:8000.

Development

Project Structure

djust/
├── crates/
│   ├── djust_core/        # Core types & utilities
│   ├── djust_templates/   # Template engine
│   ├── djust_vdom/        # Virtual DOM & diffing
│   ├── djust_components/  # Reusable component library
│   └── djust_live/        # Main PyO3 bindings
├── python/
│   └── djust/             # Python package
│       ├── live_view.py         # LiveView base class
│       ├── component.py         # Component system
│       ├── websocket.py         # WebSocket consumer
│       └── static/
│           └── client.js        # Client runtime
├── branding/                    # Logo and brand assets
├── examples/                    # Example projects
├── benchmarks/                  # Performance benchmarks
└── tests/                       # Tests

Running Tests

# All tests (Python + Rust + JavaScript)
make test

# Individual test suites
make test-python       # Python tests
make test-rust         # Rust tests
make test-js           # JavaScript tests

# Specific tests
pytest tests/unit/test_live_view.py
cargo test --workspace --exclude djust_live

For comprehensive testing documentation, see the Testing Guide.

Building Documentation

cargo doc --open

Roadmap

djust 1.0 is released and stable. Active planning lives in the issue tracker. One notable item still open:

  • React/Vue component compatibility

Security

  • CSRF protection via Django middleware
  • XSS protection via automatic template escaping (the Rust engine escapes all variables by default)
  • HTML-producing filters (urlize, urlizetrunc, unordered_list) handle their own escaping internally; the Rust engine's safe_output_filters whitelist prevents double-escaping, so |safe is never needed with these filters
  • WebSocket authentication via Django sessions
  • WebSocket origin validation and HMAC message signing
  • Per-view and global rate limiting
  • Configurable allowed origins for WebSocket connections
  • View-level auth enforcement (login_required, permission_required) before mount()
  • Handler-level @permission_required for protecting individual event handlers
  • djust_audit command and djust.S005 system check for auth-posture visibility

Report security issues to security@djust.org.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md first.

Areas where help is especially useful:

  • More example applications
  • Performance optimizations
  • Documentation improvements
  • Browser compatibility testing

Supporting djust

djust is open source (MIT licensed) and free. If you use djust in production or want to support development:

  • Star this repository to help others discover it
  • Sponsor on GitHub — from $5/month

License

MIT License — see the LICENSE file for details.

Acknowledgments

Community & Support


Maintained by the djust community.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

djust-1.0.8.tar.gz (5.4 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

djust-1.0.8-cp314-cp314-win_amd64.whl (7.9 MB view details)

Uploaded CPython 3.14Windows x86-64

djust-1.0.8-cp314-cp314-manylinux_2_34_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.34+ x86-64

djust-1.0.8-cp314-cp314-macosx_11_0_arm64.whl (7.6 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

djust-1.0.8-cp314-cp314-macosx_10_12_x86_64.whl (7.8 MB view details)

Uploaded CPython 3.14macOS 10.12+ x86-64

djust-1.0.8-cp313-cp313-win_amd64.whl (7.9 MB view details)

Uploaded CPython 3.13Windows x86-64

djust-1.0.8-cp313-cp313-manylinux_2_34_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.34+ x86-64

djust-1.0.8-cp313-cp313-macosx_11_0_arm64.whl (7.6 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

djust-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl (7.8 MB view details)

Uploaded CPython 3.13macOS 10.12+ x86-64

djust-1.0.8-cp312-cp312-win_amd64.whl (7.9 MB view details)

Uploaded CPython 3.12Windows x86-64

djust-1.0.8-cp312-cp312-manylinux_2_34_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

djust-1.0.8-cp312-cp312-macosx_11_0_arm64.whl (7.6 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

djust-1.0.8-cp312-cp312-macosx_10_12_x86_64.whl (7.8 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

djust-1.0.8-cp311-cp311-win_amd64.whl (7.9 MB view details)

Uploaded CPython 3.11Windows x86-64

djust-1.0.8-cp311-cp311-manylinux_2_34_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.34+ x86-64

djust-1.0.8-cp311-cp311-macosx_11_0_arm64.whl (7.6 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

djust-1.0.8-cp311-cp311-macosx_10_12_x86_64.whl (7.7 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

djust-1.0.8-cp310-cp310-manylinux_2_34_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.34+ x86-64

File details

Details for the file djust-1.0.8.tar.gz.

File metadata

  • Download URL: djust-1.0.8.tar.gz
  • Upload date:
  • Size: 5.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djust-1.0.8.tar.gz
Algorithm Hash digest
SHA256 2f2602dbedc8d2f50c9439cc1c973193434b75e2b0687916a1e648d90804ac70
MD5 4587dec0bb544511909f8d9b56024a26
BLAKE2b-256 fb23110d4eaa4d02084352adf3b652452d793cedda78ee8cdd26fcf06591253f

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8.tar.gz:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: djust-1.0.8-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 7.9 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djust-1.0.8-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 b8485645e88872f996028d04a9b5344edfa862b262dfe84d9a76a3a0e2123e6e
MD5 700f6712e7814fc42cef2133db6ed3d2
BLAKE2b-256 296921396382b01adcbe891bfdaa8da5672a34038a65d6802871b9d849a6747d

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp314-cp314-win_amd64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp314-cp314-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp314-cp314-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 25e7bd615d96d5777a66452721406b2e8ad83fd00e6def664350eb4c6ec9a034
MD5 25854c00b288cb83ab275bf24b492f63
BLAKE2b-256 79563a04a926b4ece4462dbcc490742e908fb6eab266a2944a8124cf564983cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp314-cp314-manylinux_2_34_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 51dc242b2c45f18c1cdcebcfc8d5b72efd895104ff750dddd198ea62426c95d5
MD5 d7c07cc56d515c7277fce723dad626ff
BLAKE2b-256 9ff2f906ce4b5b054a7cfa1b5739288391d86b06c12db1607d989c7306d0b5e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp314-cp314-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f77878cce69674b1ad60a3e1b50eaf96d36d1e069c12894fb5c0213411263d5a
MD5 70aa5f4601be2de97c4807cc2fc57b01
BLAKE2b-256 bd826f87f0ec03c6fce0da41254577b3555cc1897258fa707e6e62778f12acd3

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp314-cp314-macosx_10_12_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: djust-1.0.8-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 7.9 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djust-1.0.8-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 13b6f827caad9695d6fa78b666366733f642952daf04ed792bd6bb8584824fd1
MD5 288e60536b979c884697ff2c9e9321c5
BLAKE2b-256 be90ed8a9af6ab38bdea5734c9a4c48bced15283b7f12e216eb7a7289d9e2a3b

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp313-cp313-win_amd64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp313-cp313-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp313-cp313-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 4d9483fb157b0294fb95a046ca00e23832efe0502567e969ea39cf3f6a4aea96
MD5 3f3ad67ef8c1751cd2e3c8a1f18fadad
BLAKE2b-256 20a8081078ba789b84f6b866e49a5e83a6bbcc968ec7d8e72690fcf01bd33811

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp313-cp313-manylinux_2_34_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 54e0d5d342841dbce15288bcd0fd2ae16d15bd36e9ba922cad5f9e66cfb3fc01
MD5 f99c9713f75faf3baf02cd75e277ce24
BLAKE2b-256 154ea5864ebd6679df3a2627135755495aa1a5dcdba3d812fbc81b1b14cf0bec

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f30b942ca4f81c5edbc724ad3c2193968d3b5d6746723f462d6b190b69630ba5
MD5 9d6f2a9e6089cc4536c4aaebfbc52ecf
BLAKE2b-256 fde1896e73a1700faf355511ce51ce94e76b7795cca5f92e23032ba1bc5e84be

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: djust-1.0.8-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 7.9 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djust-1.0.8-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 c10c27d8246e798be7908740ec060ac71467a47f8df6d76626d1af46f89481f1
MD5 deae7b4fdddcc866c1078b987266916b
BLAKE2b-256 e079f1dba68acec3b70b82af3f77cae80f7caac47a6a68e3747a10d2ecc70021

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp312-cp312-win_amd64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 39db056e8f6f7a38ea053a727e4f76e05559b0f101a3d30e14062a4a98a35ad9
MD5 bd0b0e4e551fb538c0a9635a9d46e0a6
BLAKE2b-256 4fff1ee08f993c8fdaae4e895042c877132f3cd726886ce0f796083bbad896e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp312-cp312-manylinux_2_34_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6c3ade1230afcb43edd9135f3687b62e9fa846f19c656091289a5022b3613275
MD5 38e98bab03e109cb112b87c77247fa0d
BLAKE2b-256 49cd389a7367d0dbbef0abf513490e4933e94246e87a32aa98f992c3a86f1813

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c7cbe4c902dbba85814fec82dc5543eae793bb65407625866bf311367be0ab4d
MD5 29a0259ea7d2dc051e0f0375a3552b66
BLAKE2b-256 30363f7b3d2eff024091000e199aaa7e0cea7e419a3a41f305bbca466a5ecf8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp312-cp312-macosx_10_12_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: djust-1.0.8-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 7.9 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for djust-1.0.8-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 1b272870b44606b56f52a282bac48d84f217cf71b646acbd71af1799248f7eef
MD5 fb8e6cb4fdd4f585316b96111ae6ee0d
BLAKE2b-256 a88c4183c10e45b785d506f76cda95f0d771143c9f21d33c2ba25d12f169b8ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp311-cp311-win_amd64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp311-cp311-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp311-cp311-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 84bf0a164dc496ad2e70482d2f4f59b86bfee6e2120290e7bd35c80f275c5cf0
MD5 c6e48420cb60418725f932ce6c103395
BLAKE2b-256 02e414da2104474156ff4589028f763f3a892deff2678631f5c425e6e83b7103

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp311-cp311-manylinux_2_34_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7712be5e7124a417c8fc79963cd34813c8b792f15d8d915d2385bc222adc38e3
MD5 3aff38dfd3fd1a8d1bcd8f2a3fbb0534
BLAKE2b-256 d6696da4cc768e10cb02d443e329c225bac5ce719b0253dd1be7beceb623fb17

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 9edaa6d2bd4dde0269dbf1ca38587635d0d8d12d395d73dce8c5a1ecf0cdce6c
MD5 d7d247937c6e9113e1849fd76f9cfd7e
BLAKE2b-256 f528fa9831d8058548f159948512a783c962a49e2089c192da40c4617ade8786

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp311-cp311-macosx_10_12_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file djust-1.0.8-cp310-cp310-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for djust-1.0.8-cp310-cp310-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 c43f944214ccdd9f874dde6dfbf4a32cc3f7966d4d8d32fa70c73855f41ed568
MD5 027064b6c5f0c78c2f8b5692733bcce5
BLAKE2b-256 b827da7ab55fe46b44901a5f7bf2eaa40ecfc6c2f0775f6b2e0aa77bddc7f91d

See more details on using hashes here.

Provenance

The following attestation bundles were made for djust-1.0.8-cp310-cp310-manylinux_2_34_x86_64.whl:

Publisher: release.yml on djust-org/djust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page