On this page
on_mount Hooks¶
on_mount hooks let you inject shared behaviour that runs during every mount (and reconnect) of a LiveView, after authentication but before the view's own mount() method. This is the djust equivalent of Phoenix LiveView's on_mount/1 callback.
What You Get¶
- Cross-cutting concerns -- Run shared logic (auth, telemetry, tenant resolution) without repeating code in every view
- Redirect-based halting -- Return a URL string from any hook to halt the mount and redirect the client
- Inheritance -- Hooks walk the MRO parent-first and are automatically deduplicated
- V009 system check -- Catches misconfigured
on_mountattributes at startup
Basic Usage¶
1. Define a Hook Function¶
A hook is any callable with the signature (view, request, **kwargs). Return None to continue, or a redirect URL string to halt the mount chain.
from djust.hooks import on_mount
@on_mount
def require_verified_email(view, request, **kwargs):
if not request.user.email_verified:
return '/verify-email/'
The @on_mount decorator marks the function so djust recognises it as a hook. It does not change the function's behaviour -- it simply sets an internal marker attribute.
2. Attach Hooks to a LiveView¶
Set the on_mount class attribute to a list of hook functions:
from djust import LiveView
class ProfileView(LiveView):
template_name = 'profile.html'
on_mount = [require_verified_email]
def mount(self, request, **kwargs):
self.user = request.user
When ProfileView mounts, djust runs require_verified_email first. If the user's email is not verified, the client is redirected to /verify-email/ and mount() never executes.
3. Multiple Hooks¶
Hooks run in declaration order. The first hook to return a URL string wins -- subsequent hooks are skipped.
class DashboardView(LiveView):
template_name = 'dashboard.html'
on_mount = [require_auth, require_verified_email, track_page_view]
Hook Function Signature¶
def my_hook(view, request, **kwargs) -> Optional[str]:
...
| Parameter | Type | Description |
|---|---|---|
view |
LiveView instance |
The view being mounted. You can read/write state on it. |
request |
HttpRequest |
The Django request object (HTTP on initial mount, synthetic on reconnect). |
**kwargs |
dict |
URL keyword arguments from the route (e.g., pk from path("<int:pk>/", ...)). |
| Return | None or str |
None to continue the chain. A URL string to halt and redirect. |
Halting Mount with a Redirect¶
When a hook returns a string, djust treats it as a redirect URL. The mount pipeline stops immediately, mount() is never called, and the client navigates to the returned URL.
@on_mount
def require_subscription(view, request, **kwargs):
if not request.user.has_active_subscription:
return '/pricing/'
# Return None implicitly to continue
This is logged at INFO level:
on_mount hook require_subscription halted mount for DashboardView: redirect to /pricing/
Hook Inheritance¶
When a view inherits from a base that also declares on_mount, hooks are collected by walking the MRO in parent-first order. Duplicate hooks (same function object) are automatically removed.
@on_mount
def set_tenant(view, request, **kwargs):
view._tenant = request.headers.get('X-Tenant-ID')
@on_mount
def require_auth(view, request, **kwargs):
if not request.user.is_authenticated:
return '/login/'
class BaseTenantView(LiveView):
on_mount = [set_tenant, require_auth]
class SettingsView(BaseTenantView):
on_mount = [require_admin] # Added on top of parent hooks
For SettingsView, the effective hook order is:
set_tenant(fromBaseTenantView)require_auth(fromBaseTenantView)require_admin(fromSettingsView)
If SettingsView also listed set_tenant, it would not run twice -- deduplication removes the repeat.
Common Patterns¶
Authentication Guard¶
@on_mount
def require_auth(view, request, **kwargs):
if not request.user.is_authenticated:
return '/login/'
Telemetry / Analytics¶
import logging
logger = logging.getLogger(__name__)
@on_mount
def track_mount(view, request, **kwargs):
logger.info(
"LiveView mount: view=%s user=%s path=%s",
view.__class__.__name__,
getattr(request.user, 'pk', 'anonymous'),
request.path,
)
Tenant Resolution¶
@on_mount
def resolve_tenant(view, request, **kwargs):
tenant_slug = kwargs.get('tenant')
if not tenant_slug:
return '/select-tenant/'
try:
view._tenant = Tenant.objects.get(slug=tenant_slug)
except Tenant.DoesNotExist:
return '/404/'
Feature Flags¶
@on_mount
def require_feature(view, request, **kwargs):
feature = getattr(view, '_required_feature', None)
if feature and not request.user.has_feature(feature):
return '/upgrade/'
class BetaDashboard(LiveView):
_required_feature = 'beta_dashboard'
on_mount = [require_auth, require_feature]
V009 System Check¶
djust validates on_mount at startup via Django's system check framework. The check djust.V009 catches two problems:
on_mountis not a list or tuple -- e.g., accidentally assigning a single function instead of a list.- Non-callable items in the list -- e.g., a string or
Noneslipped in.
?: (djust.V009) MyView: 'on_mount' should be a list of hook functions.
HINT: Set on_mount = [hook1, hook2, ...] on your LiveView class.
These checks run automatically with python manage.py check and at server startup.
API Reference¶
@on_mount decorator¶
from djust.hooks import on_mount
Marks a function as an on_mount hook. Does not alter the function's runtime behaviour.
is_on_mount(func) -> bool¶
from djust.hooks import is_on_mount
Returns True if func was decorated with @on_mount.
run_on_mount_hooks(view_instance, request, **kwargs) -> Optional[str]¶
from djust.hooks import run_on_mount_hooks
Executes all collected hooks for the view's class in MRO order. Returns a redirect URL string if any hook halts, otherwise None. This is called internally by the LiveView mount pipeline -- you typically do not call it directly.