mirror of
https://github.com/Django-LiveView/docs.git
synced 2025-12-31 05:32:23 +01:00
Add comprehensive documentation for advanced features
- Add Script Execution section with security warnings and examples - Add File Upload Handling with Base64 encoding guide - Add Message Queue System documentation - Add Network Connectivity Handling with reconnection behavior - Add Registry Management methods (get_handler, unregister, clear, get_all_handlers) - Add WebSocket Configuration options - Add Automatic Error Handling section - Update API Reference with additional registry methods - All examples include Python code, HTML templates, and best practices
This commit is contained in:
734
one.org
734
one.org
@@ -1086,6 +1086,529 @@ liveview_registry.add_middleware(auth_middleware)
|
||||
liveview_registry.add_middleware(logging_middleware)
|
||||
#+END_SRC
|
||||
|
||||
** Script Execution
|
||||
|
||||
Execute JavaScript code directly from your Python handlers.
|
||||
|
||||
⚠️ *Security Warning:* Only execute scripts from trusted sources. Never pass user input directly to the ~script~ parameter without sanitization, as this can lead to XSS (Cross-Site Scripting) vulnerabilities.
|
||||
|
||||
*** Basic Script Execution
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_handler, send
|
||||
|
||||
@liveview_handler("show_notification")
|
||||
def show_notification(consumer, content):
|
||||
message = content["form"]["message"]
|
||||
|
||||
# Execute JavaScript to show a browser notification
|
||||
send(consumer, {
|
||||
"script": f"""
|
||||
if (Notification.permission === 'granted') {{
|
||||
new Notification('New Message', {{
|
||||
body: '{message}',
|
||||
icon: '/static/icon.png'
|
||||
}});
|
||||
}}
|
||||
"""
|
||||
})
|
||||
#+END_SRC
|
||||
|
||||
*** Combining HTML and Script
|
||||
|
||||
You can combine HTML updates with script execution:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
@liveview_handler("load_chart")
|
||||
def load_chart(consumer, content):
|
||||
import json
|
||||
chart_data = json.dumps(get_chart_data())
|
||||
|
||||
# Update HTML
|
||||
html = render_to_string("chart_container.html", {
|
||||
"chart_id": "sales-chart"
|
||||
})
|
||||
|
||||
send(consumer, {
|
||||
"target": "#chart-container",
|
||||
"html": html
|
||||
})
|
||||
|
||||
# Initialize chart with JavaScript
|
||||
send(consumer, {
|
||||
"script": f"""
|
||||
const ctx = document.getElementById('sales-chart');
|
||||
new Chart(ctx, {{
|
||||
type: 'bar',
|
||||
data: {chart_data}
|
||||
}});
|
||||
"""
|
||||
})
|
||||
#+END_SRC
|
||||
|
||||
*** Inline Scripts in HTML
|
||||
|
||||
Django LiveView automatically extracts and executes ~<script>~ tags from HTML responses:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
@liveview_handler("load_interactive_component")
|
||||
def load_interactive_component(consumer, content):
|
||||
html = '''
|
||||
<div id="counter">
|
||||
<button id="increment">Count: <span>0</span></button>
|
||||
</div>
|
||||
<script>
|
||||
let count = 0;
|
||||
document.getElementById('increment').addEventListener('click', () => {
|
||||
count++;
|
||||
document.querySelector('#increment span').textContent = count;
|
||||
});
|
||||
</script>
|
||||
'''
|
||||
|
||||
send(consumer, {
|
||||
"target": "#component-container",
|
||||
"html": html
|
||||
})
|
||||
#+END_SRC
|
||||
|
||||
The script will be automatically extracted and executed after the HTML is rendered.
|
||||
|
||||
*** Use Cases
|
||||
|
||||
- Integrating third-party JavaScript libraries (charts, maps, etc.)
|
||||
- Triggering browser APIs (notifications, geolocation, etc.)
|
||||
- Initializing complex UI components
|
||||
- Playing sounds or animations
|
||||
- Focusing specific elements with custom logic
|
||||
|
||||
*** Best Practices
|
||||
|
||||
1. ✓ Sanitize any user input before including in scripts
|
||||
2. ✓ Use JSON serialization for data: ~import json; json.dumps(data)~
|
||||
3. ✓ Prefer ~<script>~ tags in templates over the ~script~ parameter
|
||||
4. ✓ Keep scripts focused and minimal
|
||||
5. ✗ Don't use ~eval()~ or similar dangerous functions
|
||||
6. ✗ Don't pass unsanitized user input to scripts
|
||||
|
||||
** File Upload Handling
|
||||
|
||||
Handle file uploads with Base64 encoding for WebSocket transmission.
|
||||
|
||||
*** Server-Side File Processing
|
||||
|
||||
#+BEGIN_SRC python
|
||||
import base64
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
@liveview_handler("upload_avatar")
|
||||
def upload_avatar(consumer, content):
|
||||
user = consumer.scope.get("user")
|
||||
|
||||
if not user or not user.is_authenticated:
|
||||
send(consumer, {
|
||||
"target": "#upload-status",
|
||||
"html": "<p class='error'>Please log in to upload</p>"
|
||||
})
|
||||
return
|
||||
|
||||
# Get Base64 data from form
|
||||
base64_data = content["form"].get("avatar", "")
|
||||
|
||||
if not base64_data:
|
||||
send(consumer, {
|
||||
"target": "#upload-status",
|
||||
"html": "<p class='error'>No file selected</p>"
|
||||
})
|
||||
return
|
||||
|
||||
try:
|
||||
# Extract format and data
|
||||
# Format: "data:image/png;base64,iVBORw0KGgoAAAANS..."
|
||||
format_str, img_str = base64_data.split(';base64,')
|
||||
ext = format_str.split('/')[-1]
|
||||
|
||||
# Decode Base64
|
||||
img_data = base64.b64decode(img_str)
|
||||
|
||||
# Validate it's an image
|
||||
image = Image.open(BytesIO(img_data))
|
||||
|
||||
# Resize if needed
|
||||
if image.width > 500 or image.height > 500:
|
||||
image.thumbnail((500, 500), Image.Resampling.LANCZOS)
|
||||
|
||||
# Save resized image to bytes
|
||||
buffer = BytesIO()
|
||||
image.save(buffer, format=ext.upper())
|
||||
img_data = buffer.getvalue()
|
||||
|
||||
# Save to user profile
|
||||
filename = f"avatar_{user.id}.{ext}"
|
||||
user.profile.avatar.save(
|
||||
filename,
|
||||
ContentFile(img_data),
|
||||
save=True
|
||||
)
|
||||
|
||||
# Show success
|
||||
html = f'''
|
||||
<p class='success'>Avatar uploaded successfully!</p>
|
||||
<img src="{user.profile.avatar.url}" alt="Avatar" width="100">
|
||||
'''
|
||||
|
||||
send(consumer, {
|
||||
"target": "#upload-status",
|
||||
"html": html
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.error(f"Error uploading avatar: {e}")
|
||||
|
||||
send(consumer, {
|
||||
"target": "#upload-status",
|
||||
"html": "<p class='error'>Upload failed. Please try again.</p>"
|
||||
})
|
||||
#+END_SRC
|
||||
|
||||
*** HTML Template
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<div>
|
||||
<input type="file" id="avatar-upload" accept="image/*">
|
||||
<button
|
||||
data-liveview-function="upload_avatar"
|
||||
data-action="click->page#run">
|
||||
Upload Avatar
|
||||
</button>
|
||||
<div id="upload-status"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Encode file as Base64 before sending
|
||||
document.querySelector('[data-liveview-function="upload_avatar"]')
|
||||
.addEventListener('click', async (e) => {
|
||||
const fileInput = document.getElementById('avatar-upload');
|
||||
const file = fileInput.files[0];
|
||||
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
// Store Base64 in hidden input
|
||||
let hiddenInput = document.getElementById('avatar-data');
|
||||
if (!hiddenInput) {
|
||||
hiddenInput = document.createElement('input');
|
||||
hiddenInput.type = 'hidden';
|
||||
hiddenInput.name = 'avatar';
|
||||
hiddenInput.id = 'avatar-data';
|
||||
document.querySelector('div').appendChild(hiddenInput);
|
||||
}
|
||||
hiddenInput.value = reader.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
#+END_SRC
|
||||
|
||||
*** File Size Limitations
|
||||
|
||||
WebSocket has practical limits for Base64-encoded files:
|
||||
|
||||
- ✓ *Small files* (< 1MB): Images, documents, avatars
|
||||
- ⚠️ *Medium files* (1-5MB): May work but can be slow
|
||||
- ✗ *Large files* (> 5MB): Not recommended, use traditional HTTP upload
|
||||
|
||||
For large files, use a traditional HTTP POST to upload, then notify via WebSocket.
|
||||
|
||||
*** Security Considerations
|
||||
|
||||
1. ✓ Validate file types (check magic bytes, not just extensions)
|
||||
2. ✓ Limit file sizes on the server
|
||||
3. ✓ Scan files for malware if accepting from untrusted users
|
||||
4. ✓ Store files outside the web root
|
||||
5. ✓ Use unique filenames to prevent overwrites
|
||||
6. ✓ Validate image dimensions and format with Pillow/PIL
|
||||
|
||||
** Message Queue System
|
||||
|
||||
Django LiveView automatically queues messages when the WebSocket connection is not ready.
|
||||
|
||||
*** How It Works
|
||||
|
||||
When you call a LiveView handler but the WebSocket is:
|
||||
- Still connecting
|
||||
- Temporarily disconnected
|
||||
- Reconnecting after a network failure
|
||||
|
||||
The message is automatically queued and sent once the connection is restored.
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<button
|
||||
data-liveview-function="save_draft"
|
||||
data-action="click->page#run">
|
||||
Save Draft
|
||||
</button>
|
||||
#+END_SRC
|
||||
|
||||
If the user clicks "Save Draft" while offline, the message is queued. When the connection is restored, all queued messages are sent automatically in order.
|
||||
|
||||
*** User Feedback During Queueing
|
||||
|
||||
Show users when their actions are being queued:
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<div id="connection-status"></div>
|
||||
|
||||
<script>
|
||||
// Monitor connection and queue status
|
||||
setInterval(() => {
|
||||
const statusEl = document.getElementById('connection-status');
|
||||
const ws = window.myWebSocket;
|
||||
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
statusEl.innerHTML = '<span class="online">🟢 Connected</span>';
|
||||
} else if (ws && ws.readyState === WebSocket.CONNECTING) {
|
||||
statusEl.innerHTML = '<span class="connecting">🟡 Connecting...</span>';
|
||||
} else {
|
||||
statusEl.innerHTML = '<span class="offline">🔴 Disconnected</span>';
|
||||
}
|
||||
}, 1000);
|
||||
</script>
|
||||
#+END_SRC
|
||||
|
||||
** Network Connectivity Handling
|
||||
|
||||
Django LiveView automatically handles network connectivity changes.
|
||||
|
||||
*** Automatic Detection
|
||||
|
||||
The framework detects when:
|
||||
- Network goes offline (airplane mode, WiFi disconnect, etc.)
|
||||
- Network comes back online
|
||||
- Connection to the server is lost
|
||||
- Connection to the server is restored
|
||||
|
||||
*** Visual Feedback
|
||||
|
||||
Create a connection status modal that appears when connectivity is lost:
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<!-- templates/base.html -->
|
||||
{% load static %}
|
||||
{% load liveview %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-room="{% liveview_room_uuid %}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}My Site{% endblock %}</title>
|
||||
<style>
|
||||
.no-connection {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #ff6b6b;
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.no-connection--show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.no-connection--hide {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-controller="page">
|
||||
<!-- Connection status notification -->
|
||||
<div id="no-connection" class="no-connection no-connection--hide">
|
||||
⚠️ Connection lost. Reconnecting...
|
||||
</div>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
<script src="{% static 'liveview/liveview.min.js' %}" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
#+END_SRC
|
||||
|
||||
The framework automatically shows/hides this modal when connectivity changes.
|
||||
|
||||
*** Reconnection Behavior
|
||||
|
||||
When the connection is lost, Django LiveView:
|
||||
|
||||
1. Shows the ~#no-connection~ modal (if it exists)
|
||||
2. Queues any new messages
|
||||
3. Attempts to reconnect automatically
|
||||
4. Uses exponential backoff between attempts
|
||||
5. Tries up to 5 times before giving up
|
||||
|
||||
Default reconnection settings:
|
||||
|
||||
- *Initial delay:* 3 seconds
|
||||
- *Maximum attempts:* 5
|
||||
- *Backoff multiplier:* 1.5x
|
||||
- *Maximum delay:* 30 seconds
|
||||
|
||||
Reconnection delays: 3s → 4.5s → 6.75s → 10.12s → 15.18s
|
||||
|
||||
** Registry Management
|
||||
|
||||
Advanced control over LiveView handler registration.
|
||||
|
||||
*** Listing All Handlers
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_registry
|
||||
|
||||
# Get all registered handler names
|
||||
handlers = liveview_registry.list_functions()
|
||||
print(handlers) # ['say_hello', 'load_articles', 'submit_form', ...]
|
||||
#+END_SRC
|
||||
|
||||
*** Getting a Specific Handler
|
||||
|
||||
#+BEGIN_SRC python
|
||||
# Get handler by name
|
||||
handler = liveview_registry.get_handler("say_hello")
|
||||
|
||||
if handler:
|
||||
print(f"Handler found: {handler.__name__}")
|
||||
else:
|
||||
print("Handler not found")
|
||||
#+END_SRC
|
||||
|
||||
*** Unregistering Handlers
|
||||
|
||||
Remove a handler from the registry:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
# Unregister a specific handler
|
||||
liveview_registry.unregister("old_handler")
|
||||
|
||||
# Verify it's gone
|
||||
if liveview_registry.get_handler("old_handler") is None:
|
||||
print("Handler successfully unregistered")
|
||||
#+END_SRC
|
||||
|
||||
Use cases:
|
||||
- Removing deprecated handlers
|
||||
- Disabling features at runtime
|
||||
- Testing and cleanup
|
||||
|
||||
*** Clearing All Handlers
|
||||
|
||||
#+BEGIN_SRC python
|
||||
# Remove all registered handlers
|
||||
liveview_registry.clear()
|
||||
|
||||
# Verify
|
||||
print(liveview_registry.list_functions()) # []
|
||||
#+END_SRC
|
||||
|
||||
⚠️ *Warning:* This clears ALL handlers. Only use in testing or when reinitializing the application.
|
||||
|
||||
*** Dynamic Handler Registration
|
||||
|
||||
Register handlers programmatically without the decorator:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_registry, send
|
||||
|
||||
def dynamic_handler(consumer, content):
|
||||
send(consumer, {
|
||||
"target": "#result",
|
||||
"html": "<p>Dynamic handler executed!</p>"
|
||||
})
|
||||
|
||||
# Register manually
|
||||
handler_name = "dynamic_action"
|
||||
decorated_func = liveview_registry.register(handler_name)(dynamic_handler)
|
||||
|
||||
# Now callable from frontend
|
||||
# <button data-liveview-function="dynamic_action" data-action="click->page#run">
|
||||
#+END_SRC
|
||||
|
||||
** WebSocket Configuration
|
||||
|
||||
Customize WebSocket connection settings.
|
||||
|
||||
*** Custom WebSocket Path
|
||||
|
||||
Change the default WebSocket URL path:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
# routing.py
|
||||
from liveview.routing import get_liveview_path
|
||||
|
||||
websocket_urlpatterns = [
|
||||
get_liveview_path("custom/path/<str:room_name>/"),
|
||||
]
|
||||
#+END_SRC
|
||||
|
||||
Update frontend configuration:
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<!-- templates/base.html -->
|
||||
<script>
|
||||
window.webSocketConfig = {
|
||||
host: '{{ request.get_host }}',
|
||||
protocol: '{% if request.is_secure %}wss{% else %}ws{% endif %}',
|
||||
path: '/custom/path/' // Custom path
|
||||
};
|
||||
</script>
|
||||
<script src="{% static 'liveview/liveview.min.js' %}" defer></script>
|
||||
#+END_SRC
|
||||
|
||||
*** Custom Host and Protocol
|
||||
|
||||
For development or special deployments:
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<script>
|
||||
window.webSocketConfig = {
|
||||
host: 'api.example.com', // Different host
|
||||
protocol: 'wss' // Force secure WebSocket
|
||||
};
|
||||
</script>
|
||||
#+END_SRC
|
||||
|
||||
*** Reconnection Configuration
|
||||
|
||||
Modify reconnection behavior by editing ~frontend/webSocketsCli.js~ before building:
|
||||
|
||||
#+BEGIN_SRC javascript
|
||||
// frontend/webSocketsCli.js
|
||||
|
||||
// Default values:
|
||||
const RECONNECT_INTERVAL = 3000; // Initial delay: 3 seconds
|
||||
const MAX_RECONNECT_ATTEMPTS = 5; // Maximum attempts: 5
|
||||
const RECONNECT_BACKOFF_MULTIPLIER = 1.5; // Exponential multiplier
|
||||
|
||||
// Custom values (example):
|
||||
const RECONNECT_INTERVAL = 5000; // Initial delay: 5 seconds
|
||||
const MAX_RECONNECT_ATTEMPTS = 10; // Maximum attempts: 10
|
||||
const RECONNECT_BACKOFF_MULTIPLIER = 2.0; // Double delay each time
|
||||
#+END_SRC
|
||||
|
||||
Then rebuild the JavaScript:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
cd frontend
|
||||
npm run build:min
|
||||
#+END_SRC
|
||||
|
||||
* Error Handling
|
||||
:PROPERTIES:
|
||||
:ONE: one-custom-default-doc
|
||||
@@ -1412,6 +1935,136 @@ def important_operation(consumer, content):
|
||||
})
|
||||
#+END_SRC
|
||||
|
||||
** Automatic Error Handling
|
||||
|
||||
Django LiveView automatically catches and reports handler exceptions.
|
||||
|
||||
*** Built-in Error Handling
|
||||
|
||||
When a handler raises an unhandled exception, the framework automatically:
|
||||
|
||||
1. Logs the error with ~logging.error()~
|
||||
2. Sends an error message to the client
|
||||
3. Re-raises the exception for debugging
|
||||
|
||||
Example of an error that will be automatically handled:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
@liveview_handler("risky_operation")
|
||||
def risky_operation(consumer, content):
|
||||
# This will raise a ZeroDivisionError
|
||||
result = 10 / 0
|
||||
|
||||
send(consumer, {
|
||||
"target": "#result",
|
||||
"html": f"<p>Result: {result}</p>"
|
||||
})
|
||||
#+END_SRC
|
||||
|
||||
The client will automatically receive:
|
||||
|
||||
#+BEGIN_SRC json
|
||||
{
|
||||
"error": "Handler error: division by zero",
|
||||
"function": "risky_operation"
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
*** Handling Errors on the Client
|
||||
|
||||
Detect and display errors sent from the server:
|
||||
|
||||
#+BEGIN_SRC html
|
||||
<div id="result"></div>
|
||||
<div id="error-display" class="error" style="display: none;"></div>
|
||||
|
||||
<script>
|
||||
// Listen for error messages
|
||||
window.myWebSocket.addEventListener('message', (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.error) {
|
||||
// Show error to user
|
||||
const errorDiv = document.getElementById('error-display');
|
||||
errorDiv.textContent = `Error: ${data.error}`;
|
||||
errorDiv.style.display = 'block';
|
||||
|
||||
// Hide after 5 seconds
|
||||
setTimeout(() => {
|
||||
errorDiv.style.display = 'none';
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
#+END_SRC
|
||||
|
||||
*** Custom Error Responses
|
||||
|
||||
For better control, handle errors explicitly within your handler:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
@liveview_handler("safe_operation")
|
||||
def safe_operation(consumer, content):
|
||||
try:
|
||||
result = perform_calculation()
|
||||
|
||||
send(consumer, {
|
||||
"target": "#result",
|
||||
"html": f"<p class='success'>Result: {result}</p>"
|
||||
})
|
||||
|
||||
except ValueError as e:
|
||||
# Handle expected errors gracefully
|
||||
send(consumer, {
|
||||
"target": "#result",
|
||||
"html": f"<p class='error'>Invalid input: {e}</p>"
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
# Log and show generic error
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.error(f"Unexpected error: {e}", exc_info=True)
|
||||
|
||||
send(consumer, {
|
||||
"target": "#result",
|
||||
"html": "<p class='error'>An unexpected error occurred</p>"
|
||||
})
|
||||
# Don't re-raise - this prevents automatic error handling
|
||||
#+END_SRC
|
||||
|
||||
*** Configuring Error Logging
|
||||
|
||||
Configure logging for LiveView errors in ~settings.py~:
|
||||
|
||||
#+BEGIN_SRC python
|
||||
# settings.py
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'file': {
|
||||
'level': 'ERROR',
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': '/var/log/django/liveview_errors.log',
|
||||
},
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'liveview': {
|
||||
'handlers': ['file', 'mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': False,
|
||||
},
|
||||
},
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
Now all handler errors are logged to a file and emailed to admins.
|
||||
|
||||
* Testing
|
||||
:PROPERTIES:
|
||||
:ONE: one-custom-default-doc
|
||||
@@ -2285,6 +2938,87 @@ handlers = liveview_registry.list_functions()
|
||||
print(handlers) # ['say_hello', 'load_articles', ...]
|
||||
#+END_SRC
|
||||
|
||||
**** ~get_handler(function_name)~
|
||||
|
||||
Get a specific handler by name.
|
||||
|
||||
**Parameters:**
|
||||
- ~function_name~ (str): Name of the handler to retrieve
|
||||
|
||||
**Returns:** Callable or None
|
||||
|
||||
**Example:**
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_registry
|
||||
|
||||
handler = liveview_registry.get_handler("say_hello")
|
||||
|
||||
if handler:
|
||||
print(f"Handler found: {handler.__name__}")
|
||||
else:
|
||||
print("Handler not found")
|
||||
#+END_SRC
|
||||
|
||||
**** ~get_all_handlers()~
|
||||
|
||||
Get a dictionary of all registered handlers with their functions.
|
||||
|
||||
**Returns:** Dict[str, Callable]
|
||||
|
||||
**Example:**
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_registry
|
||||
|
||||
all_handlers = liveview_registry.get_all_handlers()
|
||||
|
||||
for name, func in all_handlers.items():
|
||||
print(f"Handler: {name}, Function: {func.__name__}")
|
||||
#+END_SRC
|
||||
|
||||
**** ~unregister(function_name)~
|
||||
|
||||
Remove a handler from the registry.
|
||||
|
||||
**Parameters:**
|
||||
- ~function_name~ (str): Name of the handler to remove
|
||||
|
||||
**Returns:** Callable or None (the removed handler, or None if not found)
|
||||
|
||||
**Example:**
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_registry
|
||||
|
||||
# Unregister a handler
|
||||
liveview_registry.unregister("old_handler")
|
||||
|
||||
# Verify it's gone
|
||||
if liveview_registry.get_handler("old_handler") is None:
|
||||
print("Handler successfully unregistered")
|
||||
#+END_SRC
|
||||
|
||||
**** ~clear()~
|
||||
|
||||
Remove all registered handlers.
|
||||
|
||||
**Returns:** None
|
||||
|
||||
**Example:**
|
||||
|
||||
#+BEGIN_SRC python
|
||||
from liveview import liveview_registry
|
||||
|
||||
# Remove all handlers
|
||||
liveview_registry.clear()
|
||||
|
||||
# Verify
|
||||
print(liveview_registry.list_functions()) # []
|
||||
#+END_SRC
|
||||
|
||||
⚠️ *Warning:* This clears ALL handlers. Only use in testing or when reinitializing the application.
|
||||
|
||||
** Routing
|
||||
|
||||
*** ~get_liveview_urlpatterns()~
|
||||
|
||||
Reference in New Issue
Block a user