Django app to assist with posting Ajax and receiving commands from django
Project description
Django Ajax Helpers
A Django library for building interactive AJAX-driven pages. Send commands from Django views to the browser and handle button clicks, tooltips, file uploads, and more — all without writing custom JavaScript.
Installation
pip install django-ajax-helpers
Add to INSTALLED_APPS:
INSTALLED_APPS = [
...
'ajax_helpers',
]
Quick Start
1. Include the JavaScript
In your base template:
{% load ajax_helpers %}
{% lib_include 'ajax_helpers' %}
This loads jQuery, Popper.js and the ajax_helpers JavaScript.
Alternatively, if you already have jQuery loaded:
{% load ajax_helpers %}
{% init_ajax %}
2. Add the Mixin to Your View
from ajax_helpers.mixins import AjaxHelpers
class MyView(AjaxHelpers, TemplateView):
template_name = 'my_template.html'
3. Handle a Button Click
class MyView(AjaxHelpers, TemplateView):
template_name = 'my_template.html'
def button_save(self, **kwargs):
# Do something...
return self.command_response('reload')
{% load ajax_helpers %}
{% ajax_button "Save" "save" "primary" %}
Clicking the button sends an AJAX POST to the view which calls button_save(), and the returned reload command refreshes the page.
How It Works
Ajax Helpers uses a command pattern — Django views return JSON arrays of command objects, which the JavaScript client executes in sequence.
Browser Django View
│ │
│ POST {button: "save"} │
├─────────────────────────────────────►│
│ │ button_save() called
│ [{function: "reload"}] │
│◄─────────────────────────────────────┤
│ │
│ Executes: location.reload() │
└──────────────────────────────────────┘
Python API
AjaxHelpers Mixin
The core mixin for AJAX-enabled views. Mix it into any Django class-based view.
from ajax_helpers.mixins import AjaxHelpers
class MyView(AjaxHelpers, TemplateView):
...
Command Methods
| Method | Description |
|---|---|
add_command(function_name, **kwargs) |
Append a command to the response queue |
command_response(function_name=None, **kwargs) |
Add optional final command and return the JsonResponse |
add_page_command(function_name, **kwargs) |
Add a command that runs on page load |
get_page_commands() |
Override to return a list of page load commands |
Building responses:
# Single command
return self.command_response('reload')
# Single command with parameters
return self.command_response('redirect', url='/dashboard/')
# Multiple commands
self.add_command('message', text='Saved!')
self.add_command('delay', time=1000)
return self.command_response('reload')
# Return accumulated commands without adding another
self.add_command('html', selector='#status', html='<b>Done</b>')
return self.command_response()
Page load commands (executed when the page first renders):
def get_page_commands(self):
return [
ajax_command('on', selector='#my-input', event='keyup',
keys=['Enter'], commands=[
ajax_command('ajax_post', data={'button': 'search'})
])
]
Request Routing
AJAX POST requests are automatically routed to handler methods based on the request data.
Button handlers — when the POST data contains {button: "name"}:
def button_save(self, **kwargs):
return self.command_response('reload')
def button_delete(self, pk, **kwargs):
# pk comes from the POST data
return self.command_response('message', text=f'Deleted {pk}')
Tooltip handlers — when the POST data contains {tooltip: "name"}:
def tooltip_info(self, **kwargs):
html = render_to_string('my_tooltip.html', kwargs)
return HttpResponse(html)
Timer handlers — when the POST data contains {timer: "name"}:
def timer_refresh(self, **kwargs):
return self.command_response('html', selector='#count', html=str(get_count()))
Ajax method handlers — when the POST data contains {ajax_method: "name"}:
from ajax_helpers.mixins import ajax_method
@ajax_method
def calculate(self, value1, value2):
result = int(value1) + int(value2)
return self.command_response('html', selector='#result', html=str(result))
Methods must be decorated with @ajax_method to be callable via this route.
Custom command types — extend ajax_commands to add your own routing:
class MyView(AjaxHelpers, TemplateView):
ajax_commands = ['button', 'tooltip', 'timer', 'ajax', 'action']
def action_archive(self, **kwargs):
# Called when POST contains {action: "archive"}
...
ajax_command() Utility
Build command dicts for use with add_command() or in nested command lists.
from ajax_helpers.utils import ajax_command
cmd = ajax_command('html', selector='#content', html='<p>Hello</p>')
# Returns: {'function': 'html', 'selector': '#content', 'html': '<p>Hello</p>'}
toast_commands() Utility
Generate commands to show a Bootstrap toast notification.
from ajax_helpers.utils import toast_commands
self.add_command(toast_commands(
text='Record saved successfully',
header='Success',
position='top-right', # top-left, top-right, bottom-left, bottom-right
auto_hide=True,
delay=4000,
font_awesome='fas fa-check',
))
return self.command_response()
| Parameter | Default | Description |
|---|---|---|
text |
required | Toast body text |
header |
None |
Toast header text |
header_small |
None |
Small text in header |
position |
'bottom-right' |
Corner position |
auto_hide |
True |
Auto-dismiss the toast |
delay |
4000 |
Milliseconds before auto-hide |
font_awesome |
None |
Icon class for header |
template_name |
'ajax_helpers/toast.html' |
Override toast template |
header_classes |
'' |
Extra CSS classes for header |
body_classes |
'' |
Extra CSS classes for body |
is_ajax() Utility
Check if a request is an AJAX request.
from ajax_helpers.utils import is_ajax
if is_ajax(request):
...
JavaScript Commands Reference
Commands are sent from Python and executed in the browser. Use them with command_response() or add_command().
Page Navigation
reload
Reload the current page.
return self.command_response('reload')
redirect
Navigate to a URL, optionally in a new tab.
# Same tab
return self.command_response('redirect', url='/dashboard/')
# New tab
return self.command_response('redirect', url='/report/', new_tab=True)
| Parameter | Type | Description |
|---|---|---|
url |
string | The URL to navigate to |
new_tab |
bool | If truthy, opens in a new browser tab |
DOM Manipulation
html
Set the inner HTML of an element.
self.add_command('html', selector='#content', html='<p>Updated</p>')
| Parameter | Type | Description |
|---|---|---|
selector |
string | jQuery selector |
html |
string | HTML content to set |
parent |
bool | If True, targets the parent element |
replace_with
Replace element(s) with new HTML.
self.add_command('replace_with', selector='#old-row', html='<tr>...</tr>')
| Parameter | Type | Description |
|---|---|---|
selector |
string | jQuery selector |
html |
string | Replacement HTML |
parent |
bool | If True, replaces the parent element |
append_to
Append HTML as a child of the target element.
self.add_command('append_to', selector='#list', html='<li>New item</li>')
| Parameter | Type | Description |
|---|---|---|
selector |
string | jQuery selector for the container |
html |
string | HTML to append |
remove
Remove element(s) from the DOM.
self.add_command('remove', selector='#obsolete')
Element Properties
set_value
Set the value of an input element.
self.add_command('set_value', selector='#my-input', val='Hello')
set_attr
Set an HTML attribute.
self.add_command('set_attr', selector='#link', attr='href', val='/new-url/')
set_prop
Set a DOM property.
self.add_command('set_prop', selector='#checkbox', prop='checked', val=True)
set_css
Set a CSS property.
self.add_command('set_css', selector='#box', prop='background-color', val='red')
focus
Set focus on an element.
self.add_command('focus', selector='#name-input')
User Feedback
message
Show a browser alert dialog.
return self.command_response('message', text='Something went wrong')
console_log
Log a message to the browser console.
self.add_command('console_log', text='Debug: value is 42')
clipboard
Copy text to the clipboard.
return self.command_response('clipboard', text='Copied content')
Timing
delay
Pause command processing for a given time. Sets ajax_busy to prevent overlapping requests.
self.add_command('delay', time=500)
self.add_command('reload')
return self.command_response()
| Parameter | Type | Description |
|---|---|---|
time |
int | Milliseconds to delay |
timeout
Execute nested commands after a delay.
return self.command_response('timeout', time=2000, commands=[
ajax_command('message', text='2 seconds later!')
])
| Parameter | Type | Description |
|---|---|---|
time |
int | Milliseconds to wait |
commands |
list | Commands to execute after the delay |
timer
Execute nested commands repeatedly at an interval.
self.add_page_command('timer', interval=5000, commands=[
ajax_command('ajax_post', url='/api/status/', data={'timer': 'refresh'})
], store='status_timer')
| Parameter | Type | Description |
|---|---|---|
interval |
int | Milliseconds between executions |
commands |
list | Commands to execute each interval |
always |
bool | Run even when the tab is not visible |
store |
string | Name for the timer (for later clearing) |
clear_timers
Stop all timers stored under a given name.
self.add_command('clear_timers', store='status_timer')
Conditional Execution
if_selector
Execute commands if a selector matches elements (optionally checking visibility).
self.add_command('if_selector', selector='#panel', commands=[
ajax_command('html', selector='#panel', html='Updated')
], else_commands=[
ajax_command('console_log', text='Panel not found')
])
| Parameter | Type | Description |
|---|---|---|
selector |
string | jQuery selector to test |
commands |
list | Commands if selector matches |
else_commands |
list | Commands if selector does not match |
is_visible |
bool | Also require the element to be visible |
if_not_selector
Execute commands if a selector does not match (inverse of if_selector).
self.add_command('if_not_selector', selector='#toast-container', commands=[
ajax_command('append_to', selector='body', html='<div id="toast-container"></div>')
])
Event Binding
on
Bind an event handler that executes commands.
self.add_page_command('on', selector='#search', event='keyup',
keys=['Enter'], prevent_default=True, commands=[
ajax_command('ajax_post', data={'button': 'search'})
]
)
| Parameter | Type | Description |
|---|---|---|
selector |
string | jQuery selector |
event |
string | DOM event name (e.g. 'click', 'keyup') |
commands |
list | Commands to execute on event |
keys |
list | Only trigger for these key values (for keyboard events) |
prevent_default |
bool | Call e.preventDefault() |
stop_propagation
Prevent event propagation on an element.
self.add_page_command('stop_propagation', selector='.inner-btn', event='click')
AJAX Requests
ajax_post
Send a JSON POST request to a URL.
self.add_command('ajax_post', url='/api/action/', data={'key': 'value'})
| Parameter | Type | Description |
|---|---|---|
url |
string | Target URL |
data |
dict | JSON data to send |
send_form
Submit a form via AJAX.
self.add_command('send_form', form_id='my-form')
File Operations
save_file
Trigger a file download from base64-encoded data.
import base64
data = base64.b64encode(file_bytes).decode()
return self.command_response('save_file', data=data, filename='report.pdf')
| Parameter | Type | Description |
|---|---|---|
data |
string | Base64-encoded file content |
filename |
string | Download filename |
upload_file
Used internally by the file upload system. See File Uploads.
Data Retrieval
element_count
Count matching elements and POST the count back to a URL.
self.add_command('element_count', selector='.item', data={'type': 'items'}, url='/api/count/')
get_attr
Get an element's attribute value and POST it back to a URL.
self.add_command('get_attr', selector='#target', attr='data-id', data={}, url='/api/receive/')
WebSocket
start_websocket
Open a WebSocket connection. See WebSockets.
self.add_page_command('start_websocket', ws_url='/helpers/gn-my_channel/')
No-op
null
Do nothing. Useful as a placeholder response.
return self.command_response('null')
Template Tags
Load with {% load ajax_helpers %}.
{% lib_include %}
Include CSS and JavaScript libraries.
{% lib_include 'ajax_helpers' %}
Options: cdn=True/False, module=True/False, version='x.y.z'.
{% init_ajax %}
Include just the ajax_helpers.js script (when you already have jQuery loaded).
{% init_ajax %}
{% ajax_button %}
Render a button that sends a button command via AJAX.
{% ajax_button "Save" "save" "primary" %}
{% ajax_button "Delete" "delete" css_class="btn btn-sm btn-danger" %}
Arguments: text, name, bootstrap_style (default 'primary'), css_class (overrides bootstrap_style). Extra kwargs are passed as POST data.
{% ajax_method_button %}
Render a button that calls an @ajax_method.
{% ajax_method_button "Calculate" "calculate" "success" value1="10" value2="20" %}
{% button_javascript %}
Output just the JavaScript for a button click (for use in custom onclick handlers).
<button class="btn btn-primary" onclick='{% button_javascript "save" pk=object.pk %}'>Save</button>
{% post_json_js %}
Output JavaScript for posting JSON data. Supports named URLs and blob responses.
<button onclick='{% post_json_js url_name="my_api" blob=True action="export" %}'>Export</button>
{% send_form %}
Output JavaScript to submit a form via AJAX.
<button onclick='{% send_form "my_form" extra_param="value" %}'>Submit</button>
{% send_form_button %}
Render a button that submits a form.
{% send_form_button "Submit" "my_form" "success" %}
{% upload_file %}
Render a file upload widget with optional drag-and-drop and progress bar.
{% upload_file "Choose File" "primary" drag_drop="default" progress=True %}
{% upload_file text="Upload" width="200px" height="100px" %}
| Argument | Default | Description |
|---|---|---|
text |
'Upload File' |
Button text |
bootstrap_style |
'primary' |
Bootstrap button style |
css_class |
None |
Override CSS class |
drag_drop |
None |
Enable drag-and-drop (set to 'default') |
width |
None |
Drag-drop zone width |
height |
None |
Drag-drop zone height |
progress |
False |
Show progress bar |
{% tooltip_init %}
Initialise AJAX-loaded tooltips on elements.
{% tooltip_init '.has-tooltip' 'info' 'bottom' %}
Arguments: selector, function_name, placement (optional), template (optional).
{% ajax_timer %}
Set up a periodic timer that POSTs to the view.
{% ajax_timer "refresh" 5000 %}
Arguments: name, interval_ms.
File Uploads
Use AjaxFileUploadMixin for uploading files with progress tracking.
View Setup
from ajax_helpers.mixins import AjaxHelpers, AjaxFileUploadMixin
class MyUploadView(AjaxFileUploadMixin, AjaxHelpers, TemplateView):
template_name = 'upload.html'
def upload_files(self, name, size, file, **kwargs):
# Called for each uploaded file
# name: original filename
# size: file size in bytes
# file: Django UploadedFile
save_uploaded_file(file, name)
def upload_completed(self):
self.add_command('message', text='All files uploaded')
return self.command_response('reload')
Template
{% load ajax_helpers %}
{% upload_file "Upload Files" "primary" progress=True %}
Drag and Drop
{% upload_file "Drop files here" drag_drop="default" width="300px" height="200px" progress=True %}
Configuration
| Attribute | Default | Description |
|---|---|---|
upload_key |
'ajax_modal_file' |
Form field name for uploaded file |
single_progress_bar |
True |
Use one progress bar for all files |
Celery Task Integration
Use AjaxTaskMixin to start Celery tasks and poll for results.
from ajax_helpers.mixins import AjaxHelpers, AjaxTaskMixin
from myapp.tasks import generate_report
class ReportView(AjaxTaskMixin, AjaxHelpers, TemplateView):
template_name = 'report.html'
tasks = {'report': generate_report}
refresh_ms = 1000 # poll every second (default: 600ms)
def button_generate(self, **kwargs):
return self.start_task('report', task_kwargs={'user_id': self.request.user.id})
def task_state_success(self, task_result, task_name, **kwargs):
self.add_command('message', text='Report ready!')
return self.command_response('reload')
def task_state_failure(self, task_result, task_name, **kwargs):
return self.command_response('message', text='Report generation failed')
def task_progress(self, info):
# Called on each poll while task is running
# info is task_result.info (dict)
if 'percent' in info:
self.add_command('set_css', selector='#progress', prop='width', val=f'{info["percent"]}%')
| Attribute | Default | Description |
|---|---|---|
tasks |
{} |
Dict mapping task names to Celery task classes |
refresh_ms |
600 |
Polling interval in milliseconds |
Override methods:
task_state_success(task_result, task_name, **kwargs)— task completedtask_state_failure(task_result, task_name, **kwargs)— task failedtask_state_revoked(task_result, task_name, **kwargs)— task was revokedtask_progress(info)— called on each poll while pending/running
WebSockets
Push commands to the browser in real time using Django Channels.
Consumer
from ajax_helpers.websockets.consumers import ConsumerHelper
class NotificationConsumer(ConsumerHelper):
def connect_commands(self):
# Sent to client on connection
self.add_command('message', text='Connected')
def receive(self, text_data=None, bytes_data=None):
# Handle messages from the client
pass
Routing
# routing.py
from django.urls import path
from ajax_helpers.websockets.routing import websocket_urlpatterns
# Or define your own:
websocket_urlpatterns = [
path('ws/notifications/<str:slug>/', NotificationConsumer.as_asgi()),
]
View Mixin
Send WebSocket commands from a Django view:
from ajax_helpers.websockets.mixin import WebsocketHelpers
class MyView(WebsocketHelpers, AjaxHelpers, TemplateView):
template_name = 'my_template.html'
def get_page_commands(self):
self.add_channel('notifications')
return super().get_page_commands()
def button_notify(self, **kwargs):
self.send_ws_commands('notifications', 'html',
selector='#status', html='<b>Updated!</b>')
return self.command_response('null')
Celery Task
Send WebSocket commands from a background task:
from ajax_helpers.websockets.tasks import TaskHelper
class NotifyTask(TaskHelper):
def run(self, channel_name, message):
self.send_ws_commands(channel_name, 'message', text=message)
JavaScript API
The ajax_helpers object is available globally for direct use in templates and scripts.
ajax_helpers.post_json(data)
Send a JSON POST request to the current page (or a specified URL).
// Simple button post
ajax_helpers.post_json({data: {button: 'save', pk: 42}})
// Post to a specific URL
ajax_helpers.post_json({url: '/api/action/', data: {action: 'run'}})
// With blob response (for file downloads)
ajax_helpers.post_json({data: {button: 'export'}, response_type: 'blob'})
// Custom success handler
ajax_helpers.post_json({data: {button: 'check'}, success: function(data) { console.log(data) }})
ajax_helpers.send_form(form_id, extra_data)
Submit a form as FormData via AJAX POST.
ajax_helpers.send_form('my-form', {extra_field: 'value'})
ajax_helpers.post_data(url, data, timeout, options)
POST FormData to a URL with optional progress tracking.
ajax_helpers.post_data('/upload/', formData, 0, {
progress: {selector: '#progress-bar'}
})
ajax_helpers.get_content(url)
Load a page via AJAX and push to browser history (SPA-style navigation).
ajax_helpers.get_content('/dashboard/')
ajax_helpers.process_commands(commands)
Execute an array of command objects. Commands are queued if ajax_busy is true.
ajax_helpers.process_commands([
{function: 'html', selector: '#msg', html: 'Hello'},
{function: 'focus', selector: '#input'}
])
ajax_helpers.tooltip(selector, function_name, placement, template)
Initialise lazy-loaded tooltips that fetch content from the server on hover.
ajax_helpers.tooltip('.info-icon', 'details', 'bottom')
ajax_helpers.set_ajax_busy(status, pointer_wait)
Control the busy flag and optional wait cursor.
ajax_helpers.set_ajax_busy(true, true) // busy + wait cursor
ajax_helpers.set_ajax_busy(false, true) // not busy, remove wait cursor
ajax_helpers.upload_file(selector, upload_params)
Initiate a file upload from a file input.
ajax_helpers.upload_file('#file-input', {category: 'documents'})
ajax_helpers.file_info(selector)
Get file metadata from a file input.
var files = ajax_helpers.file_info('#file-input')
// [{name: 'doc.pdf', size: 12345}, ...]
ajax_helpers.drag_drop(container_id, upload_params)
Enable drag-and-drop file uploads on a container element.
ajax_helpers.drag_drop('#drop-zone', {category: 'images'})
ajax_helpers.command_functions
The command function registry. Add custom commands:
ajax_helpers.command_functions.my_command = function(command) {
console.log('Custom command:', command.data);
};
Then from Python:
self.add_command('my_command', data='hello')
CSS Classes
| Class | Description |
|---|---|
html.wait |
Wait cursor on the entire page (set via set_ajax_busy) |
.drag_highlight |
Light blue background applied during drag-over |
.upload-dropzone |
Styled drag-and-drop zone |
.toast-danger, .toast-primary, etc. |
Bootstrap toast colour variants |
License
MIT
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 django_ajax_helpers-0.0.23.tar.gz.
File metadata
- Download URL: django_ajax_helpers-0.0.23.tar.gz
- Upload date:
- Size: 1.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25126764b9fc4f6e2e476adbff973639435657984e99a6942d96b5e6e350d574
|
|
| MD5 |
3426ec0c8a6b9cdb398370ccdf81f600
|
|
| BLAKE2b-256 |
635b12e8736e4b37ba574953e96aea8c54a3587cff25d2e8505b71f520684e15
|
Provenance
The following attestation bundles were made for django_ajax_helpers-0.0.23.tar.gz:
Publisher:
publish.yml on jonesim/ajax-helpers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_ajax_helpers-0.0.23.tar.gz -
Subject digest:
25126764b9fc4f6e2e476adbff973639435657984e99a6942d96b5e6e350d574 - Sigstore transparency entry: 2211546535
- Sigstore integration time:
-
Permalink:
jonesim/ajax-helpers@487b0c91d22fc9e2b869c226512390a06e6faee2 -
Branch / Tag:
refs/tags/v0.0.23 - Owner: https://github.com/jonesim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@487b0c91d22fc9e2b869c226512390a06e6faee2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_ajax_helpers-0.0.23-py3-none-any.whl.
File metadata
- Download URL: django_ajax_helpers-0.0.23-py3-none-any.whl
- Upload date:
- Size: 1.7 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34265aec86bd1730d8c4d16ba3724a07c8b2a7a2ce3b46027da0f78154c63995
|
|
| MD5 |
b8eb6aa6c632b1d1c68b57c952e81445
|
|
| BLAKE2b-256 |
ec3794f04bbb9154315f2b2bad7804413c47af71fbb82fd347950a7ccf915a79
|
Provenance
The following attestation bundles were made for django_ajax_helpers-0.0.23-py3-none-any.whl:
Publisher:
publish.yml on jonesim/ajax-helpers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_ajax_helpers-0.0.23-py3-none-any.whl -
Subject digest:
34265aec86bd1730d8c4d16ba3724a07c8b2a7a2ce3b46027da0f78154c63995 - Sigstore transparency entry: 2211546593
- Sigstore integration time:
-
Permalink:
jonesim/ajax-helpers@487b0c91d22fc9e2b869c226512390a06e6faee2 -
Branch / Tag:
refs/tags/v0.0.23 - Owner: https://github.com/jonesim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@487b0c91d22fc9e2b869c226512390a06e6faee2 -
Trigger Event:
push
-
Statement type: