Metadata-Version: 2.4
Name: djxi
Version: 0.1.8
Summary: Django HTMX Integration
Author-email: Philipp Rollinger <philipp.rollinger@protonmail.com>
License: MIT
Project-URL: Homepage, https://github.com/rollinger/djxi
Project-URL: Repository, https://github.com/rollinger/djxi
Project-URL: Documentation, https://djxi.readthedocs.io/
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENCE.md
Requires-Dist: django>=4.2
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: ruff>=0.0.275; extra == "dev"
Requires-Dist: pre-commit>=3.0; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Dynamic: license-file

# <img src="https://raw.githubusercontent.com/rollinger/djxi/master/assets/Djxi_logo.png" alt="djxi logo" style="width: 150px; background: white; color: black;"> **HTMX Integration for Django**

[![PyPI](https://img.shields.io/pypi/v/Djxi)](https://pypi.org/project/djxi)
[![PyPI - Wheel](https://img.shields.io/pypi/wheel/Djxi)](https://pypi.org/project/djxi)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/Djxi)](https://pypi.org/project/djxi)
[![PyPI - Django Version](https://img.shields.io/pypi/djversions/Djxi)](https://pypi.org/project/djxi)

[![CI](https://github.com/rollinger/djxi/actions/workflows/main.yml/badge.svg)](https://github.com/rollinger/djxi/actions/workflows/main.yml)
![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)
![Lint](https://img.shields.io/badge/linting-black%2Fruff-blue)
[![codecov](https://codecov.io/gh/rollinger/djxi/branch/master/graph/badge.svg)](https://codecov.io/gh/rollinger/djxi)

#### <table><td>[Read the full documentation](https://djxi.readthedocs.io/en/latest/)</td></table>

---

**Stop scrolling for scattered HTMX!**

Djxi lets you architect your HTMX features in one single **Endpoint Battery**. It bundles the urls, view logic, and the HTML into a central hub. The feature lives in one place — without scattering your code across `urls`, `views`, and `templates`.

- **No more archaeology.** No more digging through three files just to tweak a button label.  
- **Locality of Behaviour** Request → Logic → Render stays in one class.  
- **Scales cleanly.** Small partials stay manageable, without turning your project into spaghetti.
- **Django Integration.** Tags, Filters, Messages, HX-Headers, CBV and more are frictionless integrated.

## 📦 What is this?
    Just a prenup between Grandpa Django and his sexy new HTMX fling — 
    preventing scatterbrain syndrome and reactive dysfunction.

Django's Request-Render-Response cycle was architected with full page reloads in mind. The separation into views, urls and templates is practical when the response affect the whole of the client's state.

HTMX introduces minute partial updates via server-side rendered html snippets which update the page selectively and asynchronously. Those small page updates have to be orchestrated and maintained, each with its own view, url and template.

Using Django with HTMX usually results in a scattering of a multitude of template snippest, view logics and url endpoints.

Consider a simple CRUD Todo List: that is 4 urls, 4 views and 5 templates, if you do it with HTMX and create a partial for a todo item. This count can easily go up, as soon as the urge to allow in-place smart actions is given in. The number is not the problem it is the scattering of those snippets (url, view, html) over the codebase under vanilla Django best practices.

Therefore, the marriage of Django and HTMX can be bad news for [Locality of Behaviour](https://htmx.org/essays/locality-of-behaviour/) and affect maintainability of projects the more it makes use of HTMX.

### Djxi's way:
Bundle HTMX urls, views and template collection all into one or more `DXEndpointBattery`. Here the 'todo-list' feature with all it's actions is described in full in one place and obvious at a glance.
```python
from djxi import DXEndpointBattery, dx_action 

INLINE_TEMPLATE = """
<dx-section name="todo-list-container">
    <div id="todo-list-container">
        <h3>Todo List</h3>
        <input type="search" name="search" value="{{search}}"
            hx-get='{% url "todo:list" %}' hx-trigger="input changed delay:400ms" 
            hx-sync="queue last" hx-target="#todo-list-container" hx-swap="outerHTML">
        <dx-include name="todo-list">
    </div>
</dx-section>

<dx-section name="todo-list">
    <ul id="todo-list" style="list-style: none;">
        {% for item in todo_items %}
            <dx-include name="todo-item">
        {% empty %}
            <li>No todos found.</li>
        {% endfor %}
    </ul>
</dx-section>

<dx-section name="todo-item">
    ...
</dx-section>
"""

class TodoListDXBattery(DXEndpointBattery):
    inline_template = INLINE_TEMPLATE

    def get_item(self, id: int): return TodoItem.objects.get(id=id)
    def get_all(self): return TodoItem.objects.all()

    @dx_get("list", name="list")
    def list(self, request):
        item_qs = self.get_all()
        search = request.GET.get("search", "")
        if search:
            item_qs = item_qs.filter(title__icontains=search)
        return self.render_section(
            request, section_name="todo-list-container", context={"todo_items": item_qs, "search": search}
        )
    ...
```
For a full demonstration see the **todo app** in the example django project accompanying Djxi. 

Djxi is an opinionated and frictionless HTMX drop-in. It can be run in parallel to vanilla Django views and even 
alongside the way you used to integrate HTMX with Django.

`pip install djxi` and streamline new and old HTMX functionalities.

### Inline Templates?
    HTML in a multiline string? Bäh, I loose all the 
    template syntax highlighting and autocorrection!
No problem at all! Just use the `template_name` with a path to your template instead of the `inline_template`. 
With two files you still have a reasonable LoB score.

### Routing
Add the routes of the `DXEndpointBattery` via the `.url_patterns(prefix="my/prefix")` classmethod. 
You can override the `DX_ROUTER_PREFIX == 'dx'` configuration globally or individually per endpoint battery.

```python
urlpatterns = [
    ...
    path("todo/", include(TodoListDXBattery.url_patterns(prefix="htmx"))),
    ...
]
```
```bash
/todo/htmx/item/<int:item_id>/set/<str:flag>	todo.views.set_item	todo:set-item
/todo/htmx/item/new	todo.views.create	todo:add-item
/todo/htmx/list
```

### Django messaging framework
Djxi integrates fully with the `django.contrib.messages` package. 
Once set up, you can just use `messages.info(request, "Message to the user")` in your async views as well.

To set Djxi messaging up, use the `{% flash_messages_inclusion %}` templatetag where you'd like to see the messages.
You can tweak the appearance by overriding the templates in `djxi/messages/*`

### HX-Headers per middleware
Via the `djxi.middleware.DjxiHeadersMiddleware` the request and response objects have the htmx object to read incoming 
Request Headers and set outgoing Response Header to adjust HTMX on the client.

## Development Status
**Pre-Alpha Note**
The package is considered still in pre-alpha state, use with as an experimental package.
- Happy to hear from you if you like to contribute to the project.
- Watch out for updates and consider giving it a star here on GitHub.
- Checkout the djxi showcases in the example django app.
- Let me know if you used Djxi in your projects!

### Roadmap
- **v0.2.0**: Public Alpha Release; Focus improve existing facilities / coverage
- **v0.3.0**: Public Beta Release;
- **v1.0.0**: Public Release;

---

## Getting Started
### Installation
1) Install with pip:

`pip install djxi`

2) Add django-htmx to your INSTALLED_APPS:

```python
INSTALLED_APPS = [
    ...,
    "djxi",
    ...,
]
```

3) Optional: Adjust your base template to get you up and running instantly
```html
 {% load djxi %}
 <!doctype html>
 <html>
   <head>
     ...
     {% htmx_script_inclusion %}
   </head>
   <body {% htmx_headers %}>
     <div>{% flash_messages_inclusion %}</div>
     ...
   </body>
 </html>
```
The htmx_script_inclusion tag will pull the unminified v4 from CDN. Set DX_HTMX_VERSION="2" to pull in v2.
For production, you likely want to serve your own minified htmx.js.

As there are significant differences between v4 and v2 of htmx, keep DX_HTMX_VERSION in sync with what htmx version you are loading via your own staticfiles.

### Configuration
In your settings file you can override the following default values for Djxi:
- **DX_HTMX_VERSION**: "4" # allow ['2', '4']
- **DX_HTMX_COMPRESSION**: ".js"  # allow: ['.js','.min.js']
- **DX_ROUTER_PREFIX**: "dx"  # allow: str or None

Messaging Framework Integration
- **DX_MESSAGE_CONTAINER_ID**: "message-container"  # allow: CSS ID
- **DX_MESSAGE_SWAP_METHOD**: "beforeend"  # allow: htmx swap method, relative to the container id
- **DX_MESSAGE_TEMPLATE**: "djxi/messages/message_list.html"  # reroute to another template or override the djxi template
