SvelteKit-like file routing and hypermedia runtime for Django
Project description
HyperDjango
Build interactive Django apps without splitting your product into "backend API + SPA frontend".
HyperDjango keeps rendering and business logic on the server, then layers in partial swaps, signals, OOB updates, and transitions for SPA-like UX.
Problem -> Approach -> Outcome
- Problem: teams duplicate feature logic across Django views, API serializers, and frontend state stores.
- Approach: treat HTML as the interface, organize features in
hyper/, and use actions for incremental updates. - Outcome: one feature implementation path with fast interactions and fewer moving parts.
Why This Works
- Keep business logic in Django, not duplicated across REST + frontend app layers.
- Get SPA-like interactions (partial swaps, OOB updates, toasts, transitions) with HTML as the transport.
- Organize by feature using file-based routes and co-located templates/assets.
Locality of Behavior
HyperDjango is centered around a single hyper/ directory where routes, layouts, and frontend entry files live together.
hyper/
layouts/
base/
__init__.py
index.html
entry.ts
routes/
index/
page.py
index.html
partials/
flash.html
todos/
page.py
index.html
partials/
item.html
shared/
__init__.py
Each route folder owns its behavior:
page.py: server logic (get/post/@action)index.html: page templatepartials/*: fragments used by action swaps- nearby
entry.tsfiles: route/layout-specific client assets
This keeps the code you change for a feature close together.
What You Get
- file-based routing from
hyper/routes/**/+page.py - nested
layout.pycomposition - class-based pages with native
get/post/...handlers @actionmethods for hypermedia interactions- Alpine-friendly
$get/$postclient helpers - progressive enhancement for links/forms (
hyper-nav,hyper-form) - native Vite integration (dev server + build manifest)
Install
Package: https://pypi.org/project/hyperdjango/
From PyPI (recommended):
uv add hyperdjango
or:
pip install hyperdjango
Quick Start
- Add app + settings:
INSTALLED_APPS = [
# ...
"hyperdjango",
]
HYPER_FRONTEND_DIR = BASE_DIR / "hyper"
HYPER_VITE_OUTPUT_DIR = BASE_DIR / "dist"
HYPER_VITE_DEV_SERVER_URL = "http://localhost:5173/"
HYPER_DEV = DEBUG
TEMPLATES[0]["DIRS"].append(HYPER_FRONTEND_DIR)
STATICFILES_DIRS = [HYPER_VITE_OUTPUT_DIR]
- Scaffold HyperDjango into your existing project:
python manage.py hyper_scaffold
This generates hyper/ directories (including routes/, templates/, layouts/), starter files, vite.config.js, and package.json dependencies/scripts. By default it also wires your Django settings + urls file. Use --no-wire to skip patching, or --force to overwrite scaffolded files.
- If you used
--no-wire, mount routes manually inurls.py:
from django.contrib import admin
from django.urls import path
from hyperdjango.urls import include_routes
urlpatterns = [
path("admin/", admin.site.urls),
*include_routes(),
]
- Run route introspection:
python manage.py hyper_routes
Basic Page
from hyperdjango.page import HyperView
class PageView(HyperView):
def get(self, request):
return {"title": "About"}
Place this in hyper/routes/about/+page.py and create hyper/routes/about/index.html.
Note: each hyper/routes/**/+page.py must define a class named PageView (typically inheriting HyperView).
Actions
Use @action for partial updates, signal patches, toasts, OOB updates, and swap control.
from hyperdjango.actions import action
from hyperdjango.page import HyperView
class PageView(HyperView):
@action
def add(self, request, title=""):
html = self.render_block(
request=request,
block_name="todo_list",
context_updates={"items": [title]},
)
return self.action_response(
html=html,
target="#todo-list",
swap="inner",
toast={"type": "success", "message": "Added"},
)
Use HyperPageTemplate Without Routes
If you do not want file-based URL routing for a feature, create a template package in hyper/templates/** and render it from your own Django view.
from hyperdjango.page import HyperPageTemplate
class ProfileCardTemplate(HyperPageTemplate):
pass
from hyperdjango.shortcuts import render_template_page
def profile_card(request):
return render_template_page(request, ProfileCardTemplate, context={"title": "Account"})
Client Runtime
HyperDjango exposes helpers globally and as Alpine magics:
window.get(...)andwindow.post(...)- Alpine:
$get(...)and$post(...)
<div x-data="{ q: '' }">
<input x-model="q" />
<button x-on:click="$get('search', { q }, { target: '#results', key: 'search' })">
Search
</button>
</div>
Route Naming Conventions
routes/index/+page.py->/routes/about/+page.py->/aboutroutes/blog/[slug]/+page.py->/blog/<slug>routes/blog/[str__slug]/+page.py->/blog/<str:slug>routes/docs/[...path]/+page.py->/docs/<path:path>routes/accounts/reset/[uidb36]-[key]/+page.py->/accounts/reset/<uidb36>-<key>routes/account/reset/[uid__[0-9A-Za-z]+]-[key__.+]/+page.py-> inline regex segmentroutes/(marketing)/pricing/+page.py->/pricing
Reverse URL names are generated automatically (for example routes/blog/[slug]/+page.py -> hyper_blog_slug) and can be overridden per page with route_name on PageView.
Template Tags
Load tags:
{% load hyper_tags %}
Available tags:
hyper_preloadshyper_stylesheetshyper_head_scriptshyper_body_scriptshyper_custom_entry "name"
Docs
-
ReadTheDocs structure is configured via
.readthedocs.yamlanddocs/conf.py. -
Docs sections are split into Guides, Reference, and Examples/Cookbook.
Example App
A full runnable demo lives in example/.
- setup and run instructions: example/README.md
- includes routes for static, dynamic, catch-all, grouped, nested layouts
- includes action-heavy examples:
/todos,/search,/profile
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hyperdjango-0.11.0.tar.gz.
File metadata
- Download URL: hyperdjango-0.11.0.tar.gz
- Upload date:
- Size: 39.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2954db3f53b79e6303920de893d6a958b2cf82294738bdf62f07faa0298ff3a
|
|
| MD5 |
56912db49c0acd82249df40de9ff78f9
|
|
| BLAKE2b-256 |
28fb11501a58f88088e770367b55bc813d7413e49d8843c63c5e22da8e61b8a1
|
File details
Details for the file hyperdjango-0.11.0-py3-none-any.whl.
File metadata
- Download URL: hyperdjango-0.11.0-py3-none-any.whl
- Upload date:
- Size: 38.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c2c89adb794527eb221f595d714daf29a809605244982f90b86556fdff20832
|
|
| MD5 |
b5d0639c99c379a3d36b851b4a0c976a
|
|
| BLAKE2b-256 |
bba76bfa48491ac0b86ac1a82634a23d638cc605dc9ff9624ece4edfdf8c7fea
|