### Demo App Setup Instructions
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
Provides commands to install dependencies, set up the database, and run the Django development server for the demo application.
```bash
# Install and run the demo
cd code
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver
# Visit http://127.0.0.1:8000/
```
--------------------------------
### Local Development Setup
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/README.rst
Steps to set up the project locally, including installing requirements, migrating the database, and running the development server.
```bash
cd code
pip install -r requirements.txt
python manage.py migrate
python manage.py runserver
```
--------------------------------
### Install django-render-block
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/README.rst
Install the django-render-block package to enable advanced templating features for htmx patterns.
```bash
pip install django-render-block
```
--------------------------------
### Install Django Form Dependencies
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Install necessary Python packages for CSS compression, Sass compilation, and form widget manipulation in Django.
```shell
pip install django-compressor django-libsass django-widget-tweaks
```
--------------------------------
### Create a New GET Request from an Existing Request
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/view_restart.rst
This utility function creates a new HttpRequest object with the method set to GET and an empty POST data dictionary, based on an existing request. This is useful for re-rendering views without carrying over POST data.
```python
import copy
from django.http.request import HttpRequest, QueryDict
def make_get_request(request: HttpRequest) -> HttpRequest:
"""
Returns a new GET request based on passed in request.
"""
new_request = copy.copy(request)
new_request.POST = QueryDict()
new_request.method = "GET"
return new_request
```
--------------------------------
### Single Django View for Multiple Actions (POST + GET)
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This Python view combines GET rendering and POST action handling using `@for_htmx(use_block_from_params=True)`. It skips redirects for HTMX requests, allowing for seamless updates without a full page reload.
```python
# views/actions.py
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template.response import TemplateResponse
from htmx_patterns.models import Monster
from htmx_patterns.utils import for_htmx, is_htmx
@for_htmx(use_block_from_params=True)
def multiple_actions(request: HttpRequest, monster_id: int):
monster = get_object_or_404(Monster.objects.all(), id=monster_id)
if request.method == "POST":
if "kick" in request.POST:
monster.kick() # sets is_happy=False
elif "hug" in request.POST:
monster.hug() # sets is_happy=True
if not is_htmx(request):
return HttpResponseRedirect("") # normal POST/redirect/GET for non-htmx
return TemplateResponse(request, "multiple_actions.html", {"monster": monster})
```
--------------------------------
### HTML for Monster List Item
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/view_restart.rst
Example HTML structure for rendering a monster item in a list, including a checkbox and the monster's name. This is used within the Django template.
```html
{% for monster in happy_monsters %}
{% endfor %}
...
```
--------------------------------
### Security Consideration: Sensitive Information in Partials
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst
This example highlights a potential security risk where sensitive information, protected by a user permission check, might be exposed if a client can request a partial template response.
```html+django
{% if user.can_view_sensitive_info %}
```
--------------------------------
### Partial Template for Pagination Controls
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/separate_partials_single_view.rst
This HTMX-enabled partial template displays a list of items and a 'Load more' link that triggers an HTMX GET request.
```html+django
{% for monster in page_obj %}
{% endif %}
```
--------------------------------
### HTMX Configuration for Monster List Update
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
Configures an HTML element to listen for the 'monsterCreated' event. Upon receiving this event, it triggers a GET request to the current URL, targeting and replacing the '#monster-list' element with the updated content, specifically rendering the 'monster-list' block from the server.
```html
{% block monster-list %}
{% for monster in monsters %}
...
{% endfor %}
{% endblock %}
```
--------------------------------
### Handle HTMX Request and Re-render View
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/view_restart.rst
This snippet checks if the request is an HTMX request. If it is, it re-renders the monster list using a modified GET request. Otherwise, it performs an HTTP redirect.
```python
for monster in sad_monsters:
if f"sad_monster_{monster.id}" in request.POST:
monster.hug()
### New code here: ###
if is_htmx(request):
return _monster_list(make_get_request(request))
return HttpResponseRedirect("")
return TemplateResponse(
request,
"monster_list.html",
{
"happy_monsters": happy_monsters,
"sad_monsters": sad_monsters,
},
)
```
--------------------------------
### Triggering a Modal Dialog with HTMX
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
Use this button to trigger the loading of modal dialog content. It specifies the HTMX GET request, the target element, and the swap method.
```html
```
--------------------------------
### Django View for Creating Monsters with HTMX
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This view handles both GET requests to display the form and POST requests to create a new monster. It uses `Hx-Trigger` headers to signal the client to close the modal and refresh the parent list.
```python
import json
from django.forms import ModelForm
from django.http import HttpRequest, HttpResponse
from django.template.response import TemplateResponse
from htmx_patterns.models import Monster
from htmx_patterns.utils import for_htmx
class CreateMonsterForm(ModelForm):
class Meta:
model = Monster
fields = ["name", "is_happy"]
@for_htmx(use_block_from_params=True)
def main(request: HttpRequest):
# Parent page; refreshes monster list when 'monsterCreated' event fires
return TemplateResponse(request, "modals_main.html", {
"monsters": Monster.objects.all().order_by("name"),
})
@for_htmx(use_block_from_params=True)
def create_monster(request: HttpRequest):
if request.method == "POST":
form = CreateMonsterForm(request.POST)
if form.is_valid():
monster = form.save()
# Signal the client: close the dialog, refresh parent monster list
return HttpResponse(
headers={"Hx-Trigger": json.dumps({
"closeModal": True,
"monsterCreated": monster.id,
})}
)
else:
form = CreateMonsterForm()
return TemplateResponse(request, "modals_create_monster.html", {"form": form})
```
--------------------------------
### Django View for Modal Creation with HTMX Support
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
This Django view handles both GET requests to display the modal form and POST requests for form submission and validation. It uses the `@for_htmx(use_block_from_params=True)` decorator to enable specific HTMX functionality, such as returning only a block of HTML.
```python
@for_htmx(use_block_from_params=True)
def create_monster(request: HttpRequest):
if request.method == "POST":
```
--------------------------------
### Parent Page Monster List Block with HTMX Event Listener
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This Django block displays a list of monsters and listens for the 'monsterCreated' event. Upon receiving the event, it triggers a GET request to refresh its own content.
```html+django
{% block monster-list %}
{% for monster in monsters %}
{{ monster.name }}
{% endfor %}
{% endblock %}
```
--------------------------------
### HTMX View Restart Pattern in Django
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This pattern restarts a view with fresh database state for HTMX requests. It converts POST requests to GET requests internally to re-render the view without an additional HTTP round trip.
```python
from django.http import HttpRequest, HttpResponseRedirect
from django.template.response import TemplateResponse
from django.utils.functional import partition
from htmx_patterns.models import Monster
from htmx_patterns.utils import for_htmx, is_htmx, make_get_request
@for_htmx(use_block_from_params=True)
def view_restart(request: HttpRequest):
return _view_restart(request)
def _view_restart(request: HttpRequest, *, selected_happy_monsters=None, selected_sad_monsters=None):
monsters = Monster.objects.all()
sad_monsters, happy_monsters = partition(lambda m: m.is_happy, monsters)
if request.method == "POST":
selected_happy = [m for m in happy_monsters if f"happy_monster_{m.id}" in request.POST]
selected_sad = [m for m in sad_monsters if f"sad_monster_{m.id}" in request.POST]
if "kick" in request.POST:
for m in selected_happy:
m.kick()
selected_happy = []
if "hug" in request.POST:
for m in selected_sad:
m.hug()
selected_sad = []
if is_htmx(request):
# Internal restart: re-run from top with fresh DB state, no extra HTTP request
return _view_restart(
make_get_request(request), # converts POST → GET copy
selected_happy_monsters=selected_happy,
selected_sad_monsters=selected_sad,
)
return HttpResponseRedirect("")
return TemplateResponse(request, "view_restart.html", {
"happy_monsters": happy_monsters,
"sad_monsters": sad_monsters,
"selected_happy_monsters": selected_happy_monsters or [],
"selected_sad_monsters": selected_sad_monsters or [],
})
```
--------------------------------
### Django Form View with HTMX
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
A standard Django form view that handles both GET (displaying the form) and POST (processing form submission) requests. It uses TemplateResponse for rendering and redirects upon successful creation.
```python
from django.shortcuts import render, redirect
from django.template.response import TemplateResponse
from django.contrib import messages
def create_monster(request):
if request.method == "POST":
form = CreateMonsterForm(request.POST)
if form.is_valid():
monster = form.save()
messages.info(request, f"Monster {monster.name} created. You can make another.")
return redirect(".")
else:
form = CreateMonsterForm()
return TemplateResponse(request, "create_monster.html", {"form": form})
```
--------------------------------
### HTMX View Restart Pattern
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/view_restart.rst
Refactored Django view using the 'view restart' pattern for HTMX. The main view calls a helper function, passing a modified request object to simulate a GET request and avoid infinite loops.
```python
@for_htmx(use_block_from_params=True)
def monster_list(request: HttpRequest):
return _monster_list(request)
def _monster_list(request: HttpRequest):
monsters = Monster.objects.all()
sad_monsters, happy_monsters = partition(lambda m: m.is_happy, monsters)
if request.method == "POST":
if "kick" in request.POST:
for monster in happy_monsters:
if f"happy_monster_{monster.id}" in request.POST:
monster.kick()
if "hug" in request.POST:
```
--------------------------------
### Download Bulma CSS
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Download the Bulma CSS framework and save it to your project's static files. Saving with an SCSS extension is recommended for pre-processing.
```shell
curl https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.css > my_app/static/vendor/bulma.scss
```
--------------------------------
### Django View for Initial Page Load
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/separate_partials.rst
This view renders the main template, passing the list of monsters to be displayed. It serves the full page initially.
```python
def toggle_with_separate_partials(request):
return TemplateResponse(
request,
"toggle_with_separate_partials.html",
{
"monsters": Monster.objects.all(),
},
)
```
--------------------------------
### Configure Django Settings for CSS Compression
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Update Django's settings to include required apps, configure static file finders, and set up the SCSS precompiler for django-compressor.
```python
INSTALLED_APPS = [
...
"django.forms",
"compressor",
"widget_tweaks",
]
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
# other finders..
"compressor.finders.CompressorFinder",
)
STATIC_ROOT = BASE_DIR / "_static"
COMPRESS_ENABLED = True
COMPRESS_PRECOMPILERS = [("text/x-scss", "django_libsass.SassCompiler")]
```
--------------------------------
### Key Dependencies for Demo App
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
Lists essential Python packages required for the Django HTMX patterns demo application, including Django itself and specific HTMX-related libraries.
```python
# requirements.txt (key dependencies)
# Django>=4.1
# django-render-block>=0.9.1 ← required for inline partials
# django-compressor>=4.3 ← optional, for CSS/JS bundling
# django-libsass>=0.9 ← optional, for Sass/SCSS
# django-widget-tweaks>=1.4.12 ← optional, for form template filters
```
--------------------------------
### Include HTMX from Local Static Files
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/base_template.rst
Include HTMX by downloading the `htmx.min.js` file and serving it via Django's static files. This approach is useful for offline development or when CDN is not preferred.
```html+django
{% load static %}
```
--------------------------------
### HTMX Trigger Button for Adding a Monster
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This HTML button uses HTMX attributes to trigger a GET request to the monster creation endpoint, targeting the body to append the modal.
```html
```
--------------------------------
### Load More with Inline Partial Block Selection (HTML/Django)
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst
This snippet demonstrates how to implement a 'load more' functionality using HTMX. It utilizes `hx-vals` to specify which template block should be rendered and returned by the server, allowing the client to control the partial update. The target element is `#paging-area` and the swap strategy is `outerHTML`.
```html+django
{% extends "base.html" %}
{% block body %}
List of monsters
{% if page_obj.paginator.count == 0 %}
We have no monsters!
{% else %}
{% block page-and-paging-controls %}
{% for monster in page_obj %}
{% endif %}
{% endblock %}
{% endif %}
{% endblock %}
```
--------------------------------
### Django View for Inline Partial Rendering (Basic)
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst
This view checks for HTMX requests and uses `render_block_to_string` to return only the specified template block. Otherwise, it renders the full template.
```python
from render_block import render_block_to_string
def paging_with_inline_partials(request):
template_name = "paging_with_inline_partials.html"
context = {
"page_obj": get_page_by_request(request, Monster.objects.all()),
}
if request.headers.get("Hx-Request", False):
rendered_block = render_block_to_string(
template_name, "page-and-paging-controls", context=context, request=request
)
return HttpResponse(content=rendered_block)
return TemplateResponse(
request,
template_name,
context,
)
```
--------------------------------
### View for Improved Inline Partial Rendering (Python)
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst
This Python view integrates with the HTMX 'use_block' pattern by using a custom decorator `for_htmx` with `use_block_from_params=True`. This allows the view to dynamically render specific template blocks based on parameters sent with the HTMX request, simplifying the view logic.
```python
@for_htmx(use_block_from_params=True)
def paging_with_inline_partials_improved_lob(request):
return TemplateResponse(
request,
"paging_with_inline_partials_improved_lob.html",
{
"page_obj": get_page_by_request(request, Monster.objects.all()),
},
)
```
--------------------------------
### HTMX Field Row Template
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This Django template snippet renders a form field row with HTMX attributes for on-the-fly validation. It triggers a GET request to the current URL on `focusout` to validate the specific field.
```html+django
{# forms/bulma/field_row.html (simplified) #}
```
--------------------------------
### HTMX Form Validation View
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This Django view uses the `htmx_form_validate` decorator to enable per-field validation on form submission. It handles both GET requests for initial form display and POST requests for validation and saving.
```python
from htmx_patterns.form_utils import htmx_form_validate
from htmx_patterns.form_renderers import BulmaFormMixin
from django.forms import ModelForm
from django.forms.fields import DateField
from django.forms.widgets import DateInput
from htmx_patterns.models import Monster
from django.template.response import TemplateResponse
from django.shortcuts import redirect
from django.contrib import messages
class CreateMonsterForm(BulmaFormMixin, ModelForm):
date_of_birth = DateField(initial=None, widget=DateInput(attrs={"type": "date"}))
do_htmx_validation = True # opt-in flag; template reads this to add hx- attributes
class Meta:
model = Monster
fields = ["name", "is_happy", "date_of_birth", "type"]
@htmx_form_validate(form_class=CreateMonsterForm)
def form_validation(request):
if request.method == "POST":
form = CreateMonsterForm(request.POST)
if form.is_valid():
monster = form.save()
messages.info(request, f"Monster {monster.name} created.")
return redirect(".")
else:
form = CreateMonsterForm()
return TemplateResponse(request, "form_validation.html", {"form": form})
```
--------------------------------
### HTMX Form Validation Decorator for Django
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This decorator enables real-time, per-field validation for Django forms when using HTMX. It intercepts GET requests with a `_validate_field` parameter to return only the HTML for the updated field row.
```python
from functools import wraps
from django.forms import Form
from django.http import HttpResponse
def htmx_form_validate(*, form_class: type):
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if (
request.method == "GET"
and "Hx-Request" in request.headers
and (field_name := request.GET.get("_validate_field"))
):
form = form_class(request.GET)
form.is_valid() # run all validators; we'll render only one field
return HttpResponse(render_single_field_row(form, field_name))
return view_func(request, *args, **kwargs)
return wrapper
return decorator
```
--------------------------------
### HTMX Form Validation Decorator
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
A decorator that intercepts GET requests with the `Hx-Request` header and a `_validate_field` parameter. It performs validation using the specified form class and returns the rendered single field row with errors.
```python
def htmx_form_validate(*, form_class: type):
"""
Instead of a normal view, just do htmx validation using the given form class,
for a single field and return the single div that needs to be replaced.
Normally the form class will be the same class used in the view body.
"""
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if (
request.method == "GET"
and "Hx-Request" in request.headers
and (htmx_validation_field := request.GET.get("_validate_field", None))
):
form = form_class(request.GET)
form.is_valid() # trigger validation
return HttpResponse(render_single_field_row(form, htmx_validation_field))
return view_func(request, *args, **kwargs)
return wrapper
return decorator
```
--------------------------------
### Displaying Paged List with Partial Controls
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/paging_with_separate_partials.html
This template extends a base template and displays a list of monsters. It conditionally includes a partial template for paging controls if monsters exist. Use this pattern to keep your main templates clean and your paging logic reusable.
```django
{% extends "base.html" %} {% block body %}
List of monsters
================
{% if page_obj.paginator.count == 0 %}
We have no monsters!
{% else %} {% include "_page_and_paging_controls.html" %} {% endif %}
See also: [create monsters page]({% url 'simple_post_form' %})
{% endblock %}
```
--------------------------------
### CSS for Dialog Styling and Transitions
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
Provides CSS rules for styling HTML dialog elements, including overriding default behaviors, setting dimensions and positioning, and applying transitions for opacity to create fade-in effects. It also styles the dialog backdrop.
```css
dialog {
/* Override some builtins that limit us: */
max-height: 100vh;
max-width: 100vw;
/* Positioning */
box-sizing: border-box;
width: calc(100vw - 40px);
height: calc(100vh - 40px);
top: 20px;
left: 20px;
position: fixed;
margin: 0;
/* Styling */
border: 0;
border-top: 2px solid #888;
padding: 20px;
/* Fade in: */
display: flex; /* for some reason, display: block disables the transition. */
flex-direction: column;
opacity: 0;
transition: opacity 0.15s;
pointer-events: none; /* necessary or the main page becomes inaccessible after closing dialog */
}
dialog[open] {
opacity: 1;
pointer-events: inherit;
}
dialog::backdrop {
background-color: #0008;
}
```
--------------------------------
### Access HTMX Headers in Django View
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/headers.rst
Check for the 'Hx-Request' header to determine if the request was sent by HTMX. If it is an HTMX request, extract the 'Hx-Current-URL' header to get the originating URL. Otherwise, return a standard template response.
```python
def headers_demo(request):
if request.headers.get("Hx-Request", False):
current_url = request.headers["Hx-Current-URL"]
return HttpResponse(f"This is a response to a request sent by htmx from {current_url} ")
return TemplateResponse(request, "headers.html", {})
```
--------------------------------
### Django Template: Displaying a List of Monsters
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/modals_main.html
Iterates over a list of 'monsters' and displays their name and happiness status. Includes a fallback for when no monsters are present.
```html
{% block monster-list %} {% if monsters %} {% for monster in monsters %} {% endfor %} Name Happy? {{ monster.name }} {{ monster.is_happy|yesno:"Yes,No" }} {% else %} There are no monsters {% endif %} {% endblock %}
```
--------------------------------
### Django Form Widget Configuration
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Demonstrates how to configure Django form widgets to render specific HTML input types, such as setting 'date_of_birth' to render as ''. This is achieved either in the Meta class or by defining the field directly.
```python
from django.forms import ModelForm, DateField, DateInput
class CreateMonsterForm(ModelForm):
class Meta:
fields = [..., "date_of_birth"]
widgets = {
"date_of_birth": DateInput(attrs={\"type\": \"date\"}),
}
```
```python
from django.forms import ModelForm, DateField, DateInput
class CreateMonsterForm(ModelForm):
date_of_birth = DateField(widget=DateInput(attrs={\"type\": \"date\"}))
```
--------------------------------
### Base HTML Template with Compressed CSS
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Include Bulma CSS in your base HTML template using Django's compress tags for pre-processing SCSS files.
```html+django
{% load static %}
{% load compress %}
{% compress css %}
{% endcompress %}
```
--------------------------------
### Django Template: Base Structure and Block Inheritance
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/modals_main.html
Extends a base template and defines blocks for content insertion. Used for overall page structure.
```html
{% extends "base.html" %} {% load static %} {% block extrahead %} {% endblock %} {% block body %}
```
--------------------------------
### Add htmx attributes for field validation
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Conditionally add htmx attributes to a form field's container div for triggering server-side validation on focus out. This setup avoids validating file inputs and checkboxes and uses the idiomorph extension for swapping.
```html+django
{# etc #}
```
--------------------------------
### Include htmx and set global hx-headers in base template
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
Include the htmx library via CDN or local static file in your base template. Set `hx-headers` on the `` tag to globally pass the CSRF token for all POST requests.
```html+django
{# base.html #}
{% load static %}
{% block body %}{% endblock %}
```
--------------------------------
### Include HTMX via CDN in Base Template
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/base_template.rst
Use this method to quickly add HTMX to your project by linking to the Content Delivery Network. Ensure you specify a version for stability.
```html+django
...
```
--------------------------------
### SCSS Import for Bulma
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Import the Bulma CSS framework into your project's SCSS file. Custom styles can be added after the import.
```scss
@import "../vendor/bulma.scss";
// Our styles here …
body {
padding: 1rem;
}
// …
```
--------------------------------
### Conditional Block Rendering with `for_htmx` Decorator
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst
Demonstrates how to use multiple `for_htmx` decorators to conditionally render different blocks based on the `Hx-Target` header, useful for pages with multiple HTMX interactions.
```python
@for_htmx(if_hx_target="search-results", use_block="search-result-block")
@for_htmx(if_hx_target="paging-controls", use_block="page-and-paging-controls")
def my_view(request):
...
```
--------------------------------
### Use `for_htmx` decorator with `use_block_from_params`
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This option for the `for_htmx` decorator allows the template to declare the block to be rendered via `hx-vals`, improving the locality of behavior. It's recommended for better code organization.
```python
# views/partials.py
from django.template.response import TemplateResponse
from htmx_patterns.utils import for_htmx
from htmx_patterns.models import Monster
from django.core.paginator import Paginator
def get_page_by_request(request, queryset, paginate_by=6):
return Paginator(queryset, per_page=paginate_by).get_page(
request.GET.get("page")
)
# Option 3: let the template declare the block via hx-vals (best locality of behaviour)
@for_htmx(use_block_from_params=True)
def paging_with_inline_partials_lob(request):
return TemplateResponse(
request,
"paging_with_inline_partials_improved_lob.html",
{"page_obj": get_page_by_request(request, Monster.objects.all())},
)
```
--------------------------------
### HTMX Load More Button
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/_page_and_paging_controls.html
Provides a 'Load more' button that uses HTMX to fetch the next page of results. Includes logic to hide the button when there are no more pages.
```html
{% if page_obj.has_next %}
[Load more](?page={{ page_obj.next_page_number }})
{% else %}
That's all of them!
{% endif %}
```
--------------------------------
### HTML Form for Multiple Actions (No HTMX)
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/actions.rst
This HTML form uses buttons with different 'name' attributes to trigger distinct actions on the server. The 'action' attribute is set to an empty string to submit to the current URL.
```html
```
--------------------------------
### JavaScript to Show Modal on Load
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
This vanilla JavaScript listens for the 'htmx:afterSettle' event and automatically calls the `.showModal()` method on any dialog element with the `data-onload-showmodal` attribute. This ensures the modal is displayed immediately after its content is loaded.
```javascript
document.body.addEventListener("htmx:afterSettle", function(detail) {
const dialog = detail.target.querySelector('dialog[data-onload-showmodal]');
if (dialog) {
dialog.showModal();
};
});
```
--------------------------------
### Bundle HTMX with Custom JavaScript using django-compressor
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/base_template.rst
Integrate HTMX with your project's JavaScript files using django-compressor. This ensures HTMX is loaded before your custom scripts, allowing you to use the HTMX JavaScript API.
```html+django
{% compress js %}
{% endcompress %}
```
--------------------------------
### Custom Form Mixin with Renderer
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Create a form mixin that sets the custom Bulma form renderer and modifies default form behaviors, such as removing the default label suffix.
```python
class BulmaFormMixin:
default_renderer = BulmaFormRenderer()
def __init__(self, *args, **kwargs) -> None:
# We don’t want ':' as a label suffix:
return super().__init__(*args, label_suffix="", **kwargs)
```
--------------------------------
### Improved Paging with Inline Partials in Django HTMX
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This template demonstrates how to implement infinite scrolling or "load more" functionality using HTMX. It includes a loop for items and a "Load more" button that fetches and appends more content.
```html+django
{# paging_with_inline_partials_improved_lob.html #}
{% extends "base.html" %}
{% block body %}
List of monsters
{% block page-and-paging-controls %}
{% for monster in page_obj %}
{% endif %}
{% endblock %}
{% endblock %}
```
--------------------------------
### Django Template: Add Monster Link
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/modals_main.html
Placeholder for a link or button to add a new monster. Typically would link to a form or modal.
```html
Add a monster {% endblock %}
```
--------------------------------
### Single View for Paginated Content
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/separate_partials_single_view.rst
A Django view that conditionally selects the template based on the HTMX request header to serve either the full page or a partial update.
```python
def paging_with_separate_partials(request):
if request.headers.get("Hx-Request", False):
template_name = "_page_and_paging_controls.html"
else:
template_name = "paging_with_separate_partials.html"
return TemplateResponse(
request,
template_name,
{
"page_obj": get_page_by_request(request, Monster.objects.all()),
},
)
```
--------------------------------
### Define Form Renderer and Mixin Attributes
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Set template names as attributes on the form renderer and define a flag to control HTMX validation behavior. This helps in organizing logic and making HTMX validation opt-in.
```python
class BulmaFormRenderer(TemplatesSetting):
...
single_field_row_template = "forms/bulma/field_row.html"
class BulmaFormMixin:
...
do_htmx_validation = False
def get_context(self, *args, **kwargs):
return super().get_context(*args, **kwargs) | {
"do_htmx_validation": self.do_htmx_validation,
"single_field_row_template": self.renderer.single_field_row_template,
}
```
--------------------------------
### Django View for Modal Form Submission
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
Handles form submission within a modal. If the form is valid, it saves the data and returns an HttpResponse with custom 'Hx-Trigger' headers to close the modal and signal a successful creation. Otherwise, it renders the form in the modal.
```python
form = CreateMonsterForm(request.POST)
if form.is_valid():
monster = form.save()
return HttpResponse(
headers={
"Hx-Trigger": json.dumps(
{
"closeModal": True,
"monsterCreated": monster.id,
}
)
}
)
else:
form = CreateMonsterForm()
return TemplateResponse(request, "modals_create_monster.html", {"form": form})
```
--------------------------------
### Django View for HTMX Partial Update
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/separate_partials.rst
This view handles the HTMX POST request. It updates the monster's state and returns only the updated partial template for the specific item.
```python
@require_POST
def toggle_item(request, monster_id):
monster = Monster.objects.get(id=monster_id)
monster.toggle_happiness()
return TemplateResponse(request, "_toggle_item_partial.html", {"monster": monster})
```
--------------------------------
### Displaying Paginated List Items
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/_page_and_paging_controls.html
Iterates over a Django page object to display a list of items. Use this to render the current page's content.
```html
{% for monster in page_obj %}
{{ monster.name }}
{% endfor %}
```
--------------------------------
### Django HTMX Form for Multiple Actions
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This HTML template defines a form that handles both 'kick' and 'hug' actions for a monster. It uses HTMX POST requests to submit the form and update the monster's state, targeting itself for an outerHTML swap.
```html+django
{# multiple_actions.html (relevant block only) #}
{% block monster-form %}
{% endblock %}
```
--------------------------------
### HTML Form with CSRF Token for POST
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/posts.rst
Use this approach when submitting form data. Ensure the `{% csrf_token %}` tag is included within the form for security.
```html+django
Make some monsters!
```
--------------------------------
### Conditional Rendering with Django Templates
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/_toggle_item_partial.html
Use Django's `{% if %}` and `{% else %}` tags to conditionally display content based on a model's attribute. This is useful for showing different UI elements or messages.
```html
{{ monster.name }} is {% if monster.is_happy %}happy{% else %}sad{% endif %}
{% if monster.is_happy %}Kick it!{% else %}Hug it!{% endif %}
```
--------------------------------
### Use `for_htmx` decorator for partial template responses (separate template)
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
When a view is called via htmx, this decorator intercepts the `TemplateResponse` and returns only a specified partial template instead of the full page. This option uses a separate HTML file for the partial response.
```python
# views/partials.py
from django.template.response import TemplateResponse
from htmx_patterns.utils import for_htmx
from htmx_patterns.models import Monster
from django.core.paginator import Paginator
def get_page_by_request(request, queryset, paginate_by=6):
return Paginator(queryset, per_page=paginate_by).get_page(
request.GET.get("page")
)
# Option 1: switch to a separate partial template on htmx requests
@for_htmx(use_template="_page_and_paging_controls.html")
def paging_with_separate_partials(request):
return TemplateResponse(
request,
"paging_with_separate_partials.html",
{"page_obj": get_page_by_request(request, Monster.objects.all())},
)
```
--------------------------------
### Django View with Multiple POST Actions (No HTMX)
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/actions.rst
This Python view handles different POST requests based on form input names. It redirects to the same URL after processing actions. Use when not using HTMX or for non-HTMX fallbacks.
```python
def monster_detail(request: HttpRequest, monster_id: int):
monster: Monster = get_object_or_404(Monster.objects.all(), id=monster_id)
if request.method == "POST":
if "kick" in request.POST:
monster.kick()
elif "hug" in request.POST:
monster.hug()
return HttpResponseRedirect("")
return TemplateResponse(
request,
"monster_detail.html",
{
"monster": monster,
},
)
```
--------------------------------
### Django Template for Paginated Monster List
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/code/htmx_patterns/templates/paging_with_inline_partials.html
This template displays a list of monsters with pagination controls. It checks if the monster list is empty and conditionally renders the pagination. The 'page-and-paging-controls' block is designed to be used with HTMX for partial updates.
```html
{% extends "base.html" %} {% block body %}
List of monsters
================
{% if page_obj.paginator.count == 0 %}
We have no monsters!
{% else %} {% block page-and-paging-controls %} {% for monster in page_obj %}
{{ monster.name }}
{% endfor %} {% if page_obj.has_next %}
[Load more](#)
{% else %}
That's all of them!
{% endif %} {% endblock %} {% endif %}
See also: [create monsters page]({% url 'simple_post_form' %})
{% endblock %}
```
--------------------------------
### Toggle Individual Items with Separate Partial Templates in Django
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This pattern uses two Django views: one for the main page and another for a partial template that updates individual items. The partial view is called via HTMX POST requests.
```python
# views/partials.py
from django.template.response import TemplateResponse
from django.views.decorators.http import require_POST
from htmx_patterns.models import Monster
def toggle_with_separate_partials(request):
return TemplateResponse(
request,
"toggle_with_separate_partials.html",
{"monsters": Monster.objects.all()},
)
@require_POST
def toggle_item(request, monster_id):
monster = Monster.objects.get(id=monster_id)
monster.is_happy = not monster.is_happy
monster.save()
# Returns only the partial for the updated monster card
return TemplateResponse(
request,
"_toggle_item_partial.html",
{"monster": monster},
)
```
--------------------------------
### Main Template for Paginated List
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/separate_partials_single_view.rst
The main Django template includes a conditional check for content and renders the pagination controls.
```html+django
{% extends "base.html" %}
{% block body %}
List of monsters
{% if page_obj.paginator.count == 0 %}
We have no monsters!
{% else %}
{% include "_page_and_paging_controls.html" %}
{% endif %}
{% endblock %}
```
--------------------------------
### HTML Structure for a Modal Dialog with Form
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/modals.rst
This HTML defines a modal dialog containing a form. The form uses HTMX to POST data back to the same view, targeting the dialog itself for updates. It includes a submit button and renders form fields.
```html
```
--------------------------------
### Modal Template for Creating a Monster
Source: https://context7.com/spookylukey/django-htmx-patterns/llms.txt
This Django template defines the structure of the modal dialog. It uses HTMX to submit the form and targets itself for updates, with a close button.
```html+django
{# modals_create_monster.html #}
```
--------------------------------
### SCSS for Bulma Styled Inputs
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
This SCSS code uses the @extend rule to apply Bulma's input and checkbox styles to standard HTML input elements within a .field-body container. It simplifies styling by avoiding repetitive class application in templates.
```scss
@import "../vendor/bulma.scss";
.field-body {
input[type=text], input[type=email], input[type=password], input[type=date] {
@extend .input;
}
input[type=checkbox] {
@extend .checkbox;
}
}
```
--------------------------------
### Bulma Form Template
Source: https://github.com/spookylukey/django-htmx-patterns/blob/master/form_validation.rst
Customize the Django form rendering template to output HTML compatible with Bulma's form structure, including handling labels and errors.
```html+django
{% load widget_tweaks %}
{{ errors }}
{% if errors and not fields %}
{% for field in hidden_fields %}{{ field }}{% endfor %}
{% endif %}
{% for field, errors in fields %}
{% if field.label %}
{{ field.label_tag }}
{% endif %}
{% with error_class=errors|yesno:"is-danger,, " %}