On this page
Progressive Web App (PWA) Support¶
djust provides built-in PWA support for offline-first applications with automatic synchronization, service worker generation, and offline-aware template directives.
What You Get¶
- Service worker integration -- Automatic caching of HTML responses and static assets
- Offline state management -- IndexedDB/LocalStorage abstraction via mixins
- Optimistic UI updates -- Immediate feedback with sync when online
- Offline directives --
dj-offline-hide,dj-offline-show,dj-offline-disable - Automatic manifest generation -- PWA manifest with customizable settings
Quick Start¶
1. Enable PWA in Your Templates¶
{% load djust_pwa %}
<!DOCTYPE html>
<html>
<head>
{% djust_pwa_head name="My App" theme_color="#007bff" %}
</head>
<body>
{% djust_offline_indicator offline_text="You're offline" %}
{% djust_offline_styles %}
<div dj-offline-hide>Only shown when online</div>
<div dj-offline-show>Only shown when offline</div>
<button dj-offline-disable dj-click="submit">Submit</button>
</body>
</html>
2. Use PWA Mixins in Your Views¶
from djust import LiveView
from djust.pwa.mixins import PWAMixin, OfflineMixin
class MyView(OfflineMixin, LiveView):
template_name = 'app.html'
def mount(self, request):
# No enable call: inheriting OfflineMixin is what enables offline mode.
self.items = self.storage.get('items', [])
def add_item(self, name):
created = self.create_offline('Item', {'name': name})
self.items.append(created)
self.storage.set('items', self.items)
self.sync_when_online()
3. Generate the Service Worker¶
python manage.py generate_sw
PWA Mixins¶
PWAMixin¶
Base mixin for PWA functionality:
| Method | Description |
|---|---|
get_pwa_config() | PWA config dict injected into the template context |
register_pwa_handlers() | Register the install/update event handlers |
handle_install_prompt() | Called when the install prompt is shown |
handle_app_update(version) | Called when a new app version is available |
There is no enable_offline() / disable_offline() / is_offline_enabled() — inheriting the mixin is what turns the behaviour on.
OfflineMixin¶
Enhanced offline state management. It does not subclass PWAMixin — combine them explicitly (class V(OfflineMixin, PWAMixin, LiveView)) if you want both.
| Method | Description |
|---|---|
storage | Property — the OfflineStorage instance (.get(key, default) / .set(key, value)) |
sync_queue | Property — the pending SyncQueue |
create_offline(model, data) | Queue a create for sync; returns the optimistic record |
update_offline(model, obj_id, data) | Queue an update for sync |
delete_offline(model, obj_id) | Queue a delete for sync |
get_cached_or_fetch(key, queryset) | Serve from cache, else evaluate the queryset |
sync_when_online() | Drain the sync queue |
get_offline_state() | Current offline state dict |
is_online() | Always True server-side — see the note below |
handle_connection_change(online) | Connection-change hook (no built-in caller) |
There is no save_offline_state() / load_offline_state() / handle_online(); use the storage property directly.
SyncMixin¶
Automatic background synchronization. It does not subclass OfflineMixin, and it depends on storage / sync_queue being supplied by one — list it afterOfflineMixin (class V(SyncMixin, OfflineMixin, LiveView)), or the properties raise AttributeError.
| Method | Description |
|---|---|
sync_queue | Property — the pending SyncQueue; enqueue via create_offline() / update_offline() / delete_offline() |
sync_manager | Property — the SyncManager that runs the sync |
sync_<verb>_<Model>(action_data) | Your hook, e.g. sync_create_Item; case-sensitive (built as f"sync_create_{action.model}") |
Template Tags¶
{% djust_pwa_head %}¶
Complete PWA setup in one tag (manifest + service worker registration):
{% djust_pwa_head name="My App" theme_color="#007bff" %}
{% djust_pwa_manifest %}¶
Generate the PWA manifest link:
{% djust_pwa_manifest name="My App" short_name="App"
theme_color="#007bff" background_color="#ffffff" display="standalone" %}
{% djust_sw_register %}¶
Register the service worker:
{% djust_sw_register sw_url="/sw.js" scope="/" %}
{% djust_offline_indicator %}¶
Visual offline status banner:
{% djust_offline_indicator offline_text="You're offline" show_when="offline" %}
Offline Directives¶
| Directive | Behavior |
|---|---|
dj-offline-hide | Hide element when offline |
dj-offline-show | Show element only when offline |
dj-offline-disable | Disable form element when offline |
dj-offline-queued | Not implemented — no client code reads this attribute; listed here only so it is not mistaken for a working directive |
<div dj-offline-hide>
<button dj-click="save_to_server">Save</button>
</div>
<div dj-offline-show>
<p>Changes will sync when you're back online.</p>
</div>
Service Worker Configuration¶
# settings.py
DJUST_PWA = {
'MANIFEST': {
'name': 'My Application',
'short_name': 'MyApp',
'theme_color': '#007bff',
'background_color': '#ffffff',
'display': 'standalone',
'icons': [
{'src': '/static/icons/icon-192.png', 'sizes': '192x192', 'type': 'image/png'}
]
},
'SERVICE_WORKER': {
'CACHE_NAME': 'djust-v1',
'STRATEGY': 'cache-first', # or 'network-first'
'URLS_TO_CACHE': ['/static/css/app.css', '/static/js/app.js'],
'OFFLINE_URL': '/offline/',
'EXCLUDE_PATTERNS': [r'/admin/', r'/api/websocket/']
}
}
Example: Offline Todo App¶
from djust import LiveView
from djust.pwa.mixins import OfflineMixin
class TodoView(OfflineMixin, LiveView):
template_name = 'todos.html'
def mount(self, request):
self.todos = self.storage.get('todos', [])
def add_todo(self, text):
todo = self.create_offline('Todo', {'text': text, 'done': False})
self.todos.append(todo)
self.storage.set('todos', self.todos)
self.sync_when_online()
def toggle_todo(self, todo_id):
for todo in self.todos:
if todo['id'] == todo_id:
todo['done'] = not todo['done']
self.update_offline('Todo', todo_id, {'done': todo['done']})
self.storage.set('todos', self.todos)
self.sync_when_online()
Management Commands¶
# Basic generation
python manage.py generate_sw
# Custom output path
python manage.py generate_sw --output static/custom-sw.js
# Include static file collection
python manage.py generate_sw --collect-static
# Custom version
python manage.py generate_sw --version 2.1.0
Adding PWA to an Existing App¶
- Add
{% load djust_pwa %}to your base template - Include
{% djust_pwa_head %}in your<head> - Mix
PWAMixinorOfflineMixininto your LiveViews - Run
python manage.py generate_sw - Deploy with HTTPS (required for service workers in production)
Browser Support¶
| Browser | Support |
|---|---|
| Chrome / Edge | Full |
| Firefox | Full |
| Safari | Partial (no background sync) |
| Mobile Safari | Full with install prompt |
Best Practices¶
- Service workers require HTTPS in production (localhost is exempt for development).
- Use
network-firststrategy for dynamic content andcache-firstfor static assets. - Validate data in the sync queue before sending to the server.
- Consider authentication token expiry when designing offline flows.
- Test offline behavior in Chrome DevTools (Application > Service Workers > Offline).