diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e860dc7..57da2ad 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,6 +14,7 @@ repos:
- id: end-of-file-fixer
exclude_types: [text]
- id: trailing-whitespace
+ exclude_types: [markdown]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.4
hooks:
diff --git a/README.md b/README.md
index 7166e4b..4f3b301 100644
--- a/README.md
+++ b/README.md
@@ -1,271 +1,257 @@
-===================
-django-xinclude
-===================
+# django-xinclude
-.. image:: https://img.shields.io/pypi/v/django-xinclude.svg
- :target: https://pypi.org/project/django-xinclude/
- :alt: PyPI version
+[](https://pypi.org/project/django-xinclude/)
Render a template using htmx with the current context.
> [!IMPORTANT]
> This package currently contains minimal features and is a work-in-progress.
-----
+------------------------------------------------------------------------
-| ``hx-get`` is often used to delegate potentially computationally expensive template fragments to ``htmx``.
- Achieving this sometimes requires more views, each of which needs to inherit from mixins that
- provide access to the same context.
-| ``django-xinclude`` provides a template tag that aims to make this easier by leveraging the cache.
+`hx-get` is often used to delegate potentially computationally expensive
+template fragments to `htmx`.
+Achieving this sometimes requires more views, each of which needs to inherit
+from mixins that provide access to the same context.
+`django-xinclude` provides a template tag that aims to make this easier by leveraging the cache.
+## Requirements
-Requirements
-------------
-* Python 3.10 to 3.12 supported.
-* Django 4.2 to 5.0 supported.
-* `htmx `__
+- Python 3.10 to 3.12 supported.
+- Django 4.2 to 5.0 supported.
+- [htmx](https://htmx.org/)
-Setup
------
+## Setup
-* Install from **pip**:
+- Install from **pip**:
-.. code-block:: sh
+``` sh
+python -m pip install django-xinclude
+```
- python -m pip install django-xinclude
+- Add it to your installed apps:
-* Add it to your installed apps:
+``` python
+INSTALLED_APPS = [
+ ...,
+ "django_xinclude",
+ ...,
+]
+```
-.. code-block:: python
+- Include the app URLs in your root URLconf:
- INSTALLED_APPS = [
- ...,
- "django_xinclude",
- ...,
- ]
+``` python
+from django.urls import include, path
-* Include the app URLs in your root URLconf:
-
-.. code-block:: python
-
- from django.urls import include, path
-
- urlpatterns = [
- ...,
- path("__xinclude__/", include("django_xinclude.urls")),
- ]
+urlpatterns = [
+ ...,
+ path("__xinclude__/", include("django_xinclude.urls")),
+]
+```
You can use a different prefix if required.
+## Usage
-Usage
------
-
-Once installed, load the ``xinclude`` library and use the tag passing the template that you want to include:
-
-.. code-block:: html
-
- {% load xinclude %}
+Once installed, load the `xinclude` library and use the tag passing the
+template that you want to include:
- {% xinclude "footer.html" %}{% endxinclude %}
+``` html
+{% load xinclude %}
-Every feature of the regular |include|__ tag is supported, including the use of ``with`` and ``only``.
+{% xinclude "footer.html" %}{% endxinclude %}
+```
-.. |include| replace:: ``include``
-__ https://docs.djangoproject.com/en/dev/ref/templates/builtins/#include
+Every feature of the regular `include`\_\_ tag is supported, including
+the use of `with` and `only`.
You can use the following htmx-specific arguments:
-* ``hx-trigger``: corresponds to the |hx-trigger|__ htmx attribute. Defaults to ``load once``.
+- `hx-trigger`: corresponds to the `hx-trigger`\_\_ htmx attribute.
+ Defaults to `load once`.
+- `swap-time`: corresponds to the `swap` timing of the `hx-swap`\_\_
+ htmx attribute.
+- `settle-time`: corresponds to the `settle` timing of the
+ `hx-swap`\_\_ htmx attribute.
-.. |hx-trigger| replace:: ``hx-trigger``
-__ https://htmx.org/attributes/hx-trigger/
+\"Primary nodes\" may be passed along to render initial content prior to
+htmx swapping. For example:
-* ``swap-time``: corresponds to the ``swap`` timing of the |hx-swap|__ htmx attribute.
+``` html
+{% xinclude "footer.html" %}
+
Loading...
+{% endxinclude %}
+```
-.. |hx-swap| replace:: ``hx-swap``
-__ https://htmx.org/attributes/hx-swap/#timing-swap-settle
-
-* ``settle-time``: corresponds to the ``settle`` timing of the |hx-swap|__ htmx attribute.
-
-__ https://htmx.org/attributes/hx-swap/#timing-swap-settle
+`django-xinclude` plays well with the excellent
+[django-template-partials](https://github.com/carltongibson/django-template-partials/)
+package, to select specific partials on the target template.
-"Primary nodes" may be passed along to render initial content prior to htmx swapping. For example:
+### Advanced usage
-.. code-block:: html
+Below is a more complete example making use of the htmx [transition
+classes](https://htmx.org/examples/animations/#swapping). Note the
+`intersect once` trigger, which will fire the request once when the
+element intersects the viewport.
- {% xinclude "footer.html" %}
- Loading...
- {% endxinclude %}
+``` html
+
-``django-xinclude`` plays well with the excellent `django-template-partials `__
-package, to select specific partials on the target template.
+{% xinclude "magic.html" with wand="🪄" hx-trigger="intersect once" swap-time="1s" settle-time="1s" %}
+
+ Loading...
+
+{% endxinclude %}
+```
+
+`magic.html`:
+
+``` html
+
+
+
+ 🔮 {{ wand }}
+
+```
+
+------------------------------------------------------------------------
+
+You can preload the `xinclude` libary in every template by appending to
+your `TEMPLATES` `builtins` setting. This way you don't need to repeat
+the `{% load xinclude %}` in every template that you need the tag:
+
+``` python
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ # ...,
+ "OPTIONS": {
+ "builtins": [
+ "django_xinclude.templatetags.xinclude",
+ ],
+ },
+ },
+]
+```
-Advanced usage
-^^^^^^^^^^^^^^
-Below is a more complete example making use of the htmx `transition classes `__.
-Note the ``intersect once`` trigger, which will fire the request once when the element intersects the viewport.
+## How It Works
-.. code-block:: html
+`django-xinclude` first checks if it needs to render the target template
+synchronously; see the [Section below](#rendering-synchronously) for
+cases where this might be useful. If this is not the case, it stores the
+current context and the target template to the cache and constructs a
+url with a `fragment_id` that targets an internal view. It then renders
+a parent `div` element containing all the necessary htmx attributes.
+Once the htmx request fires, the view fetches the cache context and
+template that match the passed `fragment_id` and uses that context to
+render the template.
-
+### Cache
- {% xinclude "magic.html" with wand="🪄" hx-trigger="intersect once" swap-time="1s" settle-time="1s" %}
-
- Loading...
-
- {% endxinclude %}
+`django-xinclude` uses either the cache that corresponds to the
+`XINCLUDE_CACHE_ALIAS` setting, if specified, or `CACHES["default"]`.
+When setting a new cache key, it finds unpicklable values and discards
+them. If you want to see which keys get discarded, update your
+`settings.LOGGERS` to include `"django_xinclude"` with
+`"level": "DEBUG"`.
-``magic.html``:
+All official [Django cache backends](https://docs.djangoproject.com/en/5.0/ref/settings/#backend) should work, under one **important condition**:
+Your cache should be accessible from all your app instances. If you are using
+multi-processing for your Django application, or multiple servers clusters,
+make sure that your `django-xinclude` cache is accessible from all the instances,
+otherwise your requests will result in 404s.
-.. code-block:: html
+### Authorization
-
+The request user is expected to be the one that initially accessed the
+original view (and added to cache), or `AnonymousUser` in both cases;
+otherwise `django-xinclude` will return 404 for the htmx requests. If
+`request.user` is not available, for instance when `django.contrib.auth`
+is not in the `INSTALLED_APPS`, then `django-xinclude` assumes that the
+end user can access the data.
-
- 🔮 {{ wand }}
-
+### Rendering synchronously
-----
+There are cases where you might want to conditionally render fragments
+synchronously (i.e. use the regular `include`). For example, you could
+render synchronously for SEO purposes, when robots are crawling your
+pages, but still make use of the htmx functionality for regular users.
+`django-xinclude` supports this, it checks for a `xinclude_sync`
+attribute on the request and renders synchronously if that evaluates to
+`True`. So you can add a custom middleware that sets the `xinclude_sync`
+attribute upon your individual conditions.
-You can preload the ``xinclude`` libary in every template by appending to your ``TEMPLATES`` ``builtins`` setting.
-This way you don't need to repeat the ``{% load xinclude %}`` in every template that you need the tag:
+See also [Configuration](#configuration) below for the
+`XINCLUDE_SYNC_REQUEST_ATTR` setting.
-.. code-block:: python
+## Configuration
- TEMPLATES = [
- {
- "BACKEND": "django.template.backends.django.DjangoTemplates",
- # ...,
- "OPTIONS": {
- "builtins": [
- "django_xinclude.templatetags.xinclude",
- ],
- },
- },
- ]
-
-
-How It Works
-------------
-``django-xinclude`` first checks if it needs to render the target template synchronously;
-see the `Section below <#rendering-synchronously>`__ for cases where this might be useful.
-If this is not the case, it stores the current context and the target template to the cache and constructs a url
-with a ``fragment_id`` that targets an internal view. It then renders a parent ``div`` element containing all the
-necessary htmx attributes. Once the htmx request fires, the view fetches the cache context and template that match
-the passed ``fragment_id`` and uses that context to render the template.
-
-Cache
-^^^^^
-``django-xinclude`` uses either the cache that corresponds to the ``XINCLUDE_CACHE_ALIAS`` setting, if specified,
-or ``CACHES["default"]``.
-When setting a new cache key, it finds unpicklable values and discards them.
-If you want to see which keys get discarded, update your ``settings.LOGGERS`` to include ``"django_xinclude"``
-with ``"level": "DEBUG"``.
-
-| All official `Django cache backends `__ should work,
- under one **important condition**:
-| Your cache should be accessible from all your app instances. If you are using multi-processing for your Django application,
- or multiple servers clusters, make sure that your ``django-xinclude`` cache is accessible from all the instances,
- otherwise your requests will result in 404s.
-
-Authorization
-^^^^^^^^^^^^^
-The request user is expected to be the one that initially accessed the original view (and added to cache),
-or ``AnonymousUser`` in both cases; otherwise ``django-xinclude`` will return 404 for the htmx requests.
-If ``request.user`` is not available, for instance when ``django.contrib.auth`` is not in the ``INSTALLED_APPS``,
-then ``django-xinclude`` assumes that the end user can access the data.
-
-Rendering synchronously
-^^^^^^^^^^^^^^^^^^^^^^^
-There are cases where you might want to conditionally render fragments synchronously (i.e. use the regular ``include``).
-For example, you could render synchronously for SEO purposes, when robots are crawling your pages, but still make use
-of the htmx functionality for regular users. ``django-xinclude`` supports this, it checks for a ``xinclude_sync``
-attribute on the request and renders synchronously if that evaluates to ``True``.
-So you can add a custom middleware that sets the ``xinclude_sync`` attribute upon your individual conditions.
-
-See also `Configuration <#configuration>`__ below for the ``XINCLUDE_SYNC_REQUEST_ATTR`` setting.
-
-Configuration
--------------
-
-``XINCLUDE_CACHE_ALIAS: str``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The cache alias that ``django-xinclude`` will use, it defaults to ``CACHES["default"]``.
-
-``XINCLUDE_CACHE_TIMEOUT: int``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The number of seconds that contexts will remain in cache. If the setting is not present, Django will
-use the default timeout argument of the appropriate backend in the ``CACHES`` setting.
-
-``XINCLUDE_SYNC_REQUEST_ATTR: str``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The request attribute that ``django-xinclude`` will check on to determine if it needs to render synchronously.
-It defaults to ``xinclude_sync``.
-
-Running the tests
------------------
+### `XINCLUDE_CACHE_ALIAS: str`
-Fork, then clone the repo:
+The cache alias that `django-xinclude` will use, it defaults to
+`CACHES["default"]`.
-.. code-block:: sh
+### `XINCLUDE_CACHE_TIMEOUT: int`
- git clone git@github.com:your-username/django-xinclude.git
+The number of seconds that contexts will remain in cache. If the setting
+is not present, Django will use the default timeout argument of the
+appropriate backend in the `CACHES` setting.
-Set up a venv:
+### `XINCLUDE_SYNC_REQUEST_ATTR: str`
-.. code-block:: sh
+The request attribute that `django-xinclude` will check on to determine
+if it needs to render synchronously. It defaults to `xinclude_sync`.
- python -m venv .venv
- source .venv/bin/activate
- python -m pip install -e '.[tests,dev]'
+## Running the tests
-Set up the |pre-commit|__ hooks:
+Fork, then clone the repo:
-.. |pre-commit| replace:: ``pre-commit``
-__ https://pre-commit.com/
+``` sh
+git clone git@github.com:your-username/django-xinclude.git
+```
-.. code-block:: sh
+Set up a venv:
- pre-commit install
+``` sh
+python -m venv .venv
+source .venv/bin/activate
+python -m pip install -e '.[tests,dev]'
+```
-Then you can run the tests with the |just|__ command runner:
+Set up the `pre-commit`\_\_ hooks:
-.. |just| replace:: ``just``
-__ https://github.com/casey/just
+``` sh
+pre-commit install
+```
-.. code-block:: sh
+Then you can run the tests with the `just`\_\_ command runner:
- just test
+``` sh
+just test
+```
Or with coverage:
-.. code-block:: sh
-
- just coverage
-
-If you don't have ``just`` installed, you can look in the ``justfile`` for the
-commands that are run.
-
-|
+``` sh
+just coverage
+```
-Complementary packages
-----------------------
-* |django-htmx|__: Extensions for using Django with htmx.
-* |django-template-partials|__: Reusable named inline partials for the Django Template Language.
+If you don't have `just` installed, you can look in the `justfile` for
+the commands that are run.
-.. |django-htmx| replace:: ``django-htmx``
-__ https://github.com/adamchainz/django-htmx
+## Complementary packages
-.. |django-template-partials| replace:: ``django-template-partials``
-__ https://github.com/carltongibson/django-template-partials/
+- `django-htmx`\_\_: Extensions for using Django with htmx.
+- `django-template-partials`\_\_: Reusable named inline partials for
+ the Django Template Language.