Skip to main content

Djade

https://img.shields.io/github/actions/workflow/status/adamchainz/djade/main.yml.svg?branch=main&style=for-the-badge https://img.shields.io/pypi/v/djade.svg?style=for-the-badge pre-commit
You can have any colour you like, as long as it’s jade.

A Django template formatter.

You can have any colour you like, as long as it’s [d]jade.

Djade formats Django template syntax with a style based on the template style guide in Django’s documentation. It does not format HTML or other templated languages.

Djade is fast because it is built in Rust: benchmarked taking 20ms to format 377 templates.

Read more in the introductory post, or below.


Improve your Django and Git skills with my books.


Installation

Use pip:

python -m pip install djade

Python 3.11 to 3.14 supported.

pre-commit hook

You can also install Djade as a pre-commit hook.

First, add the following to the repos section of your .pre-commit-config.yaml file (docs):

-   repo: https://github.com/adamchainz/djade-pre-commit
    rev: ""  # Replace with the latest tag on GitHub
    hooks:
    -   id: djade

Djade attempts to parse your current Django version from pyproject.toml. If this doesn’t work for you, specify your target version with the --target-version option:

 -   id: djade
+    args: [--target-version, "5.2"]   # Replace with Django version

The separate repository (djade-pre-commit) enables installation without compiling the Rust code.

The default configuration uses pre-commit’s files option to pick up all text files in directories called templates (source). You may wish to override this if you have templates in different directories by adding files to the hook configuration in your .pre-commit-config.yaml file.

Second, format your entire project:

pre-commit run djade --all-files

Check these changes for any potential Djade bugs and commit them. Try git diff --ignore-all-space to check non-whitespace changes.

Third, consider adding the previous commit SHA to a .git-blame-ignore-revs file. This will prevent the initial formatting commit from showing up in git blame.

Keep the hook installed to continue formatting your templates. pre-commit’s autoupdate command will upgrade Djade so you can take advantage of future features.

Usage

djade is a command line tool that rewrites files in place. Pass a list of template files to format them:

$ djade templates/engine.html
1 file reformatted

Djade can also upgrade some old template syntax, up to a target Django version, which may be specified with the --target-version option. When --target-version is not specified, Djade attempts to detect the target version from a pyproject.toml in the current directory. If found, it attempts to parse your current minimum-supported Django version from project.dependencies, supporting formats like django>=5.2,<6.0. When available, it reports:

$ django-upgrade example.py
Detected Django version from pyproject.toml: 6.0
1 file reformatted

If this doesn’t work, no upgrade fixers are applied, unless you pass --target-version with a Django version formatted as <major>.<minor>:

$ djade --target-version 6.0 templates/engine.html
1 file reformatted

Djade does not have any ability to recurse through directories. Use the pre-commit integration, globbing, or another technique to apply it to many files. For example, with git ls-files | xargs:

git ls-files -z -- '*.html' | xargs -0r djade

…or PowerShell’s ForEach-Object:

git ls-files -- '*.html' | %{djade $_}

The filename - makes Djade read from standard input and write to standard output. In this case, Djade always exits with code 0, even if changes were made.

Options

--target-version

Optional: the version of Django to target, in the format <major>.<minor>. If provided, Djade enables its fixers for versions up to and including the target version. See the list of available versions with djade --help.

--check

Avoid writing any formatted files back. Instead, exit with a non-zero status code if any files would have been modified, and zero otherwise.

Formatting

Djade aims to format Django template syntax in a consistent, clean way. It wants to be like Black: opinionated and free of configuration. Djade’s style is based on the rules listed in the Django contribution style guide’s template style section, plus some more.

Djade does not aim to format the host language of templates (HTML, etc.). That is a much broader scope and hard to do without semantic changes. For example, whitespace is significant in some HTML contexts, such as in <pre> tags, so even adjusting indentation can affect the meaning.

Below are the rules that Djade implements.

Rules from the Django style guide:

  • Single spaces at the start and end of variables and tags:

    -{{train}}
    +{{ train }}
    
    -{%  blow whistle  %}
    +{% blow whistle %}
  • Label {% endblock %} tags that aren’t on the same line as their opening {% block %} tag:

     {% block funnel %}
     ...
    -{% endblock %}
    +{% endblock funnel %}
  • Sort libraries in {% load %} tags:

    -{% load coal boiler %}
    +{% load boiler coal %}
  • Inside variables, no spaces around filters:

    -{{ fire | stoke }}
    +{{ fire|stoke }}
  • Inside tags, single spaces between tokens:

    -{% if  locomotive  ==  'steam engine'  %}
    +{% if locomotive == 'steam engine' %}
  • Unindent top-level {% block %} and {% endblock %} tags when {% extends %} is used:

    -  {% extends 'engine.html' %}
    +{% extends 'engine.html' %}
    
    -  {% block boiler %}
    +{% block boiler %}
       ...
    -  {% endblock boiler %}
    +{% endblock boiler %}

Extra rules:

  • No leading empty lines:

    -
     {% extends 'engine.html' %}
     ...
  • No trailing empty lines:

     ...
     {% endblock wheels %}
    -
    -
  • Single spaces at the start and end of comments:

    -{#choo choo#}
    +{# choo choo #}
  • Label {% endpartialdef %} tags that aren’t on the same line as their opening {% partialdef %} tag:

    {% partialdef whistle %}
    ...
    -{% endpartialdef %}
    +{% endpartialdef whistle %}
  • No labels in {% endblock %} tags on the same line as their opening {% block %} tag:

    -{% block funnel %}...{% endblock funnel %}
    +{% block funnel %}...{% endblock %}
  • No labels in {% endpartialdef %} tags on the same line as their opening {% partialdef %} tag:

    -{% partialdef whistle %}...{% endpartialdef whistle %}
    +{% partialdef whistle %}...{% endpartialdef %}
  • Merge consecutive {% load %} tags:

    -{% load boiler %}
    -
    -{% load coal %}
    +{% load boiler coal %}
  • Sort loaded items in {% load ... from .. %} tags:

-{% load steam heat from boiler %}
+{% load heat steam from boiler %}
  • Unindent {% extends %} tags:

    -  {% extends 'engine.html' %}
    +{% extends 'engine.html' %}
  • Exactly one blank line between top-level {% block %} and {% endblock %} tags when {% extends %} is used:

 {% extends 'engine.html' %}

-
 {% block funnel %}
   ...
 {% endblock funnel %}
+
 {% block boiler %}
   ...
 {% endblock boiler %}

Fixers

Djade applies the below fixes based on the target Django version from --target-version.

Django 4.2+: length_is -> length

From the release note:

The length_is template filter is deprecated in favor of length and the == operator within an {% if %} tag.

Djade updates usage of the deprecated filter within if tags, without other conditions, appropriately:

-{% if engines|length_is:1 %}
+{% if engines|length == 1 %}

Django 4.1+: empty ID json_script fixer

From the release note:

The HTML <script> element id attribute is no longer required when wrapping the json_script template filter.

Djade removes the argument where json_script is passed an empty string, to avoid emitting id="":

-{% tracks|json_script:"" %}
+{% tracks|json_script %}

Django 3.1+: trans -> translate, blocktrans / endblocktrans -> blocktranslate / endblocktranslate

From the release note:

The renamed translate and blocktranslate template tags are introduced for internationalization in template code. The older trans and blocktrans template tags aliases continue to work, and will be retained for the foreseeable future.

Djade updates the deprecated tags appropriately:

-{% load blocktrans trans from i18n %}
+{% load blocktranslate translate from i18n %}

-{% trans "Engine colours" %}
+{% translate "Engine colours" %}

-{% blocktrans with colour=engine.colour %}
+{% blocktranslate with colour=engine.colour %}
 This engine is {{ colour }}.
-{% endblocktrans %}
+{% endblocktranslate %}

Django 3.1+: ifequal and ifnotequal -> if

From the release note:

The {% ifequal %} and {% ifnotequal %} template tags are deprecated in favor of {% if %}.

Djade updates the deprecated tags appropriately:

-{% ifequal engine.colour 'blue' %}
+{% if engine.colour == 'blue' %}
 Thomas!
-{% endifequal %}
+{% endif %}

-{% ifnotequal engine.colour 'blue' %}
+{% if engine.colour != 'blue' %}
 Not Thomas.
-{% endifnotequal %}
+{% endif %}

Django 2.1+: admin_static and staticfiles -> static

From the release note:

{% load staticfiles %} and {% load admin_static %} are deprecated in favor of {% load static %}, which works the same.

Djade updates {% load %} tags appropriately:

-{% load staticfiles %}
+{% load static %}

-{% load admin_static %}
+{% load static %}

Django 1.3+: legacy variable assignment syntax

The minimum target Django version is 2.1, so this fixer is always active.

Django 1.3 added support for = to assign variables in {% with %} and {% blocktranslate %} tags. Prior to this, they only supported the legacy syntax using the as keyword, which Django still supports.

Djade rewrites the older as syntax to the newer = one:

-{% with engines.count as total %}
+{% with total=engines.count %}
     ...
 {% endwith %}

-{% blocktranslate with engine.colour as colour %}
+{% blocktranslate with colour=engine.colour %}
     ...
 {% endblocktranslate %}

Metadata

Release files for djade 1.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for djade 1.10.0
File Size Uploaded Provenance Actions
djade-1.10.0.tar.gz 40.6 kB With provenance Details for djade-1.10.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for djade 1.10.0
File Actions
djade-1.10.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details for djade-1.10.0-py3-none-win_arm64.whl
djade-1.10.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for djade-1.10.0-py3-none-win_amd64.whl
djade-1.10.0-py3-none-musllinux_1_1_x86_64.whl Python 3 none Linux musl 1.1+ x86-64 Details for djade-1.10.0-py3-none-musllinux_1_1_x86_64.whl
djade-1.10.0-py3-none-musllinux_1_1_aarch64.whl Python 3 none Linux musl 1.1+ ARM64 Details for djade-1.10.0-py3-none-musllinux_1_1_aarch64.whl
djade-1.10.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details for djade-1.10.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
djade-1.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl Python 3 none Linux glibc 2.17+ ARMv7l Details for djade-1.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
djade-1.10.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details for djade-1.10.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
djade-1.10.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for djade-1.10.0-py3-none-macosx_11_0_arm64.whl
djade-1.10.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details for djade-1.10.0-py3-none-macosx_10_12_x86_64.whl

Total release size: 9.5 MB

Release files / djade-1.10.0.tar.gz

Download URL djade-1.10.0.tar.gz
Size 40.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9d8af77a03000914b516d6be0967b5043094db5a91cec22649f689ee5bf2e5de
BLAKE2b-256 checksum
How to use checksums
d11b9586c504ad29124d73ec36f017cc1b00c1a2f52a75fd0ee26daf51943cf2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-win_arm64.whl

Download URL djade-1.10.0-py3-none-win_arm64.whl
Size 969.3 kB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
6a90bfe2a6bf727f1b74e6dc437d692af03af90f0ca1f341c214316989bfe19d
BLAKE2b-256 checksum
How to use checksums
0b7e87bcce4ba8535b172975275e83bef598adc264da240fd2ee568dbfea9b62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-win_amd64.whl

Download URL djade-1.10.0-py3-none-win_amd64.whl
Size 1.0 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
db12e7984177cded7be4a2f2a05ab7f706760c98d3e31843260e8c13e098017a
BLAKE2b-256 checksum
How to use checksums
63d3deb5c3709a7b95f0d59cb871d343be2877eb57fb61b774bff9b7e027af6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-musllinux_1_1_x86_64.whl

Download URL djade-1.10.0-py3-none-musllinux_1_1_x86_64.whl
Size 1.2 MB
Tags Linux musl 1.1+ x86-64 Python 3
SHA-256 checksum
How to use checksums
8b282469e60ab3c57339c6b0aaf6c485d60bfab4b00185cdc789ca9244a82948
BLAKE2b-256 checksum
How to use checksums
cc20c430c35c189a7b70172ec8a63b4cca2f0fb8dcc898bd302632bb7adaf7c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-musllinux_1_1_aarch64.whl

Download URL djade-1.10.0-py3-none-musllinux_1_1_aarch64.whl
Size 1.1 MB
Tags Linux musl 1.1+ ARM64 Python 3
SHA-256 checksum
How to use checksums
c3dd024a345f5bccf2f02ad66d4ebd4f2e3727645b94b718b1cbc104d9e429b8
BLAKE2b-256 checksum
How to use checksums
58443f1bee2974b346573a824faca7fb81ec0f612a6b48fda68096a773840cd1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL djade-1.10.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.1 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
abf32c9029090f33852d5735609ed99d9e470aef6e350001bc0c77bb11b63694
BLAKE2b-256 checksum
How to use checksums
6a625524f7fb5453d303478ac1945c313cb5a7087b0391908565c301e159b3bb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl

Download URL djade-1.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Size 1.0 MB
Tags Linux glibc 2.17+ ARMv7l Python 3
SHA-256 checksum
How to use checksums
c13ea6759c346aa8c2af8db9ce9cc542754c4475e4942006811adebada90efb8
BLAKE2b-256 checksum
How to use checksums
e5be7aaa11d584f944643ddf2c69bf9067fba94d1760d2946efb71aabc7df57e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL djade-1.10.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.0 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
22119928123641e7fe017d3465d3018302d4124ae7c378bf982cf485e06803e1
BLAKE2b-256 checksum
How to use checksums
14043480d4e5e423ed97f5ffa6f9e39ccab1a1e7a9e5bdf56b0ccd081e089c7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-macosx_11_0_arm64.whl

Download URL djade-1.10.0-py3-none-macosx_11_0_arm64.whl
Size 987.7 kB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
72923f91485d319ca643796a82a92b85caab26d75caf2c1b7338cd17147418ce
BLAKE2b-256 checksum
How to use checksums
388de7fd0f8a821ac80f5aa50d11a27e86fda6f411175e6635a28f0738227286
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / djade-1.10.0-py3-none-macosx_10_12_x86_64.whl

Download URL djade-1.10.0-py3-none-macosx_10_12_x86_64.whl
Size 1.1 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
a65f833034e702d130f92b7c8a13262c2182051e4fd51d808a3469a55b2082e3
BLAKE2b-256 checksum
How to use checksums
deb773ed82c9dc87fa10e5dc500f1250c78c4afdc0528733ea29b66a894f5ce3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Security for djade 1.10.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 10 files in this release have been uploaded with provenance metadata.

Select from 10 files

Attestation for djade-1.10.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page