Skip to main content

A fast, HTML aware, Django template formatter, written in Rust.

Project description

Djangofmt

Pypi Version License Supported Python Versions Actions status pre-commit.ci status

A fast, HTML aware, Django template formatter, written in Rust.

Heavily rely on the awesome markup_fmt with some additions to support Django fully.

Installation

djangofmt is available on PyPI.

# With pip
pip install djangofmt

# With uv
uv tool install djangofmt@latest  # Install djangofmt globally.
uv add --dev djangofmt            # Or add djangofmt to your project.

# With pipx
pipx install djangofmt

As a pre-commit hook

See pre-commit for instructions

Sample .pre-commit-config.yaml:

- repo: https://github.com/UnknownPlatypus/djangofmt-pre-commit
  rev: v0.2.0
  hooks:
    - id: djangofmt

The separate repository enables installation without compiling the Rust code.

By default, the configuration uses pre-commit’s files option to detect all text files in directories named templates. If your templates are stored elsewhere, you can override this behavior by specifying the desired files in the hook configuration within your .pre-commit-config.yaml file.

Usage

Usage: djangofmt [OPTIONS] <FILES>...

Arguments:
  <FILES>...
          List of files to format

Options:
      --line-length <LINE_LENGTH>
          Set the line-length [default: 120]
      --profile <PROFILE>
          Template language profile to use [default: django] [possible values: django, jinja]
      --custom-blocks <BLOCK_NAMES>
          Comma-separated list of custom block name to enable
  -h, --help
          Print help
  -V, --version
          Print version

Djangofmt 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, git ls-files | xargs:

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

…or PowerShell’s ForEach-Object:

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

Controlling the formatting

DjangoFmt gives users control over formatting in cases where static analysis struggles to determine the optimal approach.

Splitting an opening tag across multiple lines

You can control this formatting by choosing whether to insert a newline before the first attribute:

# Unchanged
<div class="flex" id="great" data-a>
  This is nice!
</div>

# Wrap on multiple lines
<div
-    class="flex" id="great" data-a>
+    class="flex"
+    id="great"
+    data-a
+>
    This is nice!
</div>

Class attribute formatting

The class attribute will be formatted as a space-separated sequence of strings, unless there are already newlines inside the attribute value.

This makes it possible to accommodate the 2 following use cases:

<div class="
  mt-8 p-8
  bg-indigo-600 hover:bg-indigo-700
  border border-transparent
  font-medium text-white
">
    Hello world
</div>

<div class="mt-8 p-8 bg-indigo-600 hover:bg-indigo-700 border border-transparent font-medium text-white">
    Hello world
</div>

See https://github.com/g-plane/markup_fmt/issues/75#issuecomment-2456526352 for the rationale.

Known limitations

All of these could be solved but were not prioritized for now.

style attributes formatting

The style attribute will be formatted using a CSS formatter (Malva), but the output will always be on a single line.

Before:

<div class="flex flex-col items-center absolute z-10"
     style="top:60%;
            transform:translate(0,-50%)">
    Such a lovely day
</div>

After:

<div class="flex flex-col items-center absolute z-10"
     style="top:60%; transform:translate(0,-50%)">
    Such a lovely day
</div>

Benchmarks

Here are the results benchmarking djangofmt against similar tools on 100k lines of HTML across 1.7k files.

Shows a bar chart with benchmark results.

Formatting 100k+ lines of HTML across 1.7k+ files from scratch.

This is important to note that only djlint covers the same scope in terms of formatting capabilities. djade only alter django templating, djhtml only fix indentation and prettier only understand html (and will break templates)

As always, these results should be taken with a grain of salt. Results on my machine will differ from yours, especially if you have many CPU cores because some tools take better advantage of parallelization than others.

But at least it was fun to build thanks to the wonderful hyperfine tool.

Benchmark details (2025-02-28)

This was run on my AMD Ryzen 9 7950X (32) @ 5.881GHz.

Tools versions:

  • djangofmt: v0.1.0
  • prettier: v3.5.2
  • djlint: v1.36.4
  • djade: v1.3.2
  • djhtml: v3.0.7
Benchmark 1: cat /tmp/test-files | xargs --max-procs=0 ../../target/release/djangofmt format --profile django --line-length 120 --quiet
  Time (mean ± σ):      19.8 ms ±   0.9 ms    [User: 179.6 ms, System: 73.7 ms]
  Range (min … max):    18.3 ms …  23.3 ms    73 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: cat /tmp/test-files | xargs --max-procs=0 djade --target-version 5.1
  Time (mean ± σ):      72.0 ms ±   1.0 ms    [User: 63.2 ms, System: 9.3 ms]
  Range (min … max):    70.5 ms …  73.4 ms    18 runs

Benchmark 3: cat /tmp/test-files | xargs --max-procs=0 djhtml
  Time (mean ± σ):      1.401 s ±  0.026 s    [User: 1.322 s, System: 0.079 s]
  Range (min … max):    1.373 s …  1.453 s    10 runs

Benchmark 4: cat /tmp/test-files | xargs --max-procs=0 djlint --reformat --profile=django --max-line-length 120
  Time (mean ± σ):      2.343 s ±  0.026 s    [User: 64.944 s, System: 1.176 s]
  Range (min … max):    2.297 s …  2.377 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 5: cat /tmp/test-files | xargs --max-procs=0 ./node_modules/.bin/prettier --ignore-unknown --write --print-width 120 --log-level silent
  Time (mean ± σ):      3.226 s ±  0.062 s    [User: 4.481 s, System: 0.261 s]
  Range (min … max):    3.092 s …  3.292 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  cat /tmp/test-files | xargs --max-procs=0 ../../target/release/djangofmt format --profile django --line-length 120 --quiet ran
    3.63 ± 0.17 times faster than cat /tmp/test-files | xargs --max-procs=0 djade --target-version 5.1
   70.71 ± 3.45 times faster than cat /tmp/test-files | xargs --max-procs=0 djhtml
  118.28 ± 5.48 times faster than cat /tmp/test-files | xargs --max-procs=0 djlint --reformat --profile=django --max-line-length 120
  162.80 ± 7.96 times faster than cat /tmp/test-files | xargs --max-procs=0 ./node_modules/.bin/prettier --ignore-unknown --write --print-width 120 --log-level silent

Shell Completions

You can generate shell completions for your preferred shell using the djangofmt completions command.

Usage: djangofmt completions <SHELL>

Arguments:
  <SHELL>
      The shell to generate the completions for
      [possible values: bash, elvish, fish, nushell, powershell, zsh]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

djangofmt-0.2.0.tar.gz (73.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

djangofmt-0.2.0-py3-none-win_arm64.whl (1.4 MB view details)

Uploaded Python 3Windows ARM64

djangofmt-0.2.0-py3-none-win_amd64.whl (1.5 MB view details)

Uploaded Python 3Windows x86-64

djangofmt-0.2.0-py3-none-win32.whl (1.3 MB view details)

Uploaded Python 3Windows x86

djangofmt-0.2.0-py3-none-musllinux_1_2_x86_64.whl (1.6 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

djangofmt-0.2.0-py3-none-musllinux_1_2_i686.whl (1.6 MB view details)

Uploaded Python 3musllinux: musl 1.2+ i686

djangofmt-0.2.0-py3-none-musllinux_1_2_armv7l.whl (1.4 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

djangofmt-0.2.0-py3-none-musllinux_1_2_aarch64.whl (1.4 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

djangofmt-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

djangofmt-0.2.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ s390x

djangofmt-0.2.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

djangofmt-0.2.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl (1.7 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64

djangofmt-0.2.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl (1.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ i686

djangofmt-0.2.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (1.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

djangofmt-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

djangofmt-0.2.0-py3-none-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

djangofmt-0.2.0-py3-none-macosx_10_12_x86_64.whl (1.5 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

djangofmt-0.2.0-py3-none-linux_armv6l.whl (1.4 MB view details)

Uploaded Python 3

File details

Details for the file djangofmt-0.2.0.tar.gz.

File metadata

  • Download URL: djangofmt-0.2.0.tar.gz
  • Upload date:
  • Size: 73.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.7

File hashes

Hashes for djangofmt-0.2.0.tar.gz
Algorithm Hash digest
SHA256 73eb57e0e21ff4f02851086220766505fe2e29b8f58c4c50354c0fb21d1e7945
MD5 49ec17f0b2798a96263c209846cc71ff
BLAKE2b-256 5b660d62b18f40363fb3bc10b6ab644d4aaa14a5d6ba7881010b0e123af76a2a

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-win_arm64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 1798cb16a8b8633f71e685b8c2e3810bf01fb23029af0219dcf8a83e33e085a7
MD5 b7b8b1d63e01591d020faaddc6c30b95
BLAKE2b-256 d711b9446e01d2ad00fe7cfa62c0eefba473397e21aedeaed993c77bfb63448c

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 0a16fb64559d89db13f9ccd6bbde2b848e7bf2fdf6ba14477c0bf431eb04ff72
MD5 ca7542f3bce2055b8cb1d1fc87c36c4b
BLAKE2b-256 f68506bda2b7bcd1df7807e1b2548d98535afecd2a6f4fb17ebb71b11a89839c

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-win32.whl.

File metadata

  • Download URL: djangofmt-0.2.0-py3-none-win32.whl
  • Upload date:
  • Size: 1.3 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.7

File hashes

Hashes for djangofmt-0.2.0-py3-none-win32.whl
Algorithm Hash digest
SHA256 c549372ca4bdecd6d6ae489a67f4a5b60513502908149395d75adfa0662f9bb2
MD5 5728b8ac79ad89783c321b291890471e
BLAKE2b-256 a58b3f0f80f29fb468699a8b880c7d3088fa193317d198c95aae270cef3641c7

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 03886dd8ec8485648e9475799c6dace24f34208ea2245b725dc5b8cf7e8f17eb
MD5 364dd4a23ae8015834bb7c5f285659a1
BLAKE2b-256 b5cff380a9630e3ad2fede0ca1951058e826840df33c80f0915f96ebdbc0be34

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 66eec5ae6ecbd3dabfb0b4dea8e8921c29a7e1d35c79559c8bb2d4bb37b2692d
MD5 1527e1007e071f40ec1261e86c312aa9
BLAKE2b-256 1ecb470c2eea23dbdbef271418d4a2c8a531b52816da865e62fa72701a3bc2f7

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 7b9ffcc1a15afae3b7791fe0665ba235fb236be46d04281a6c5012b3c1821096
MD5 365bb3dd103bcc64563ebabaf5bf255c
BLAKE2b-256 54fbe5c204aae93c0df0e5dc365b8268dbf252a8595b9749a922806974ab79ab

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 d2fd37150e50441afb693315f8a745d640ee7e4ab85cf37a9a569db66185a0b5
MD5 a298b4e9fbeb239af7db0c6a9feb85da
BLAKE2b-256 a43d05e00e9e4b1b927846f304254245170b6504d453b3ad3855ee51dd896637

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 cbe3bee4567ecd30f2a2d5e9fefb38e0a422661761886ec86d8fde16ba6b48cf
MD5 e8d3e67e12facb6b77e1b7ed2d313d99
BLAKE2b-256 7f87344633d865a1c620af8d8cb4683fea045192a50cc38d6a977f700a9aa7fa

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 b26e32bd0248dac88c1464d208490ab76d424fe275e1c75b4bc0e4044ced0b0d
MD5 68f3127fd2f77a11fe9c2ab603d4959c
BLAKE2b-256 807f82f7663ec635f9266f10773144a84aebf78c737c81b8632fd006d3b9cba4

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 e065e461d6685e6fb25f9c5b79e238d249a054699b8812a183d0860fb8ee81b9
MD5 56f4b0f3fb192cc95fb0420a5a50b6aa
BLAKE2b-256 c9fb2667df9273400171ec216647c44a4753ce1cdd6405eb8adb7733efefa1e2

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 5a0ba4056068586552f4047a9860a933138e8b2d4cae74b2dca7b9705fd93102
MD5 2f7dc60024b6d3b54f6a9c1de50c1885
BLAKE2b-256 b8e4802b160cae3dd70025657d688e362770c479829fe0e252c84957d7b28938

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 8da450f00c1b5a6e4d960fe0af3e124a18e474c81cc8b483a4c3e91651e7e0ec
MD5 529ea554ccce54780df5190c67fff0a5
BLAKE2b-256 d373541c7f58d88056a94004aec900b67e6234ec23ab5226788d7f10b2ac7eeb

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 f51d1b11d69bf034cbe174c6498b97a199989fef5c889ff2186eaf403a0e26f3
MD5 9771c705265f0be31c1a6ea2b9c57c7b
BLAKE2b-256 683156e1f38ab2d9c8486a7e5b0bdeee74af6c17cf1eb32254f83579af32c0d1

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3c9f1f7f28dfd1d54ed9660e280865881615ce7b7abd5acda4d01b859c890d24
MD5 abc31d0929e70ef0288a3a9c539d15dc
BLAKE2b-256 030229141496412aeb1fe2c9a58e9be3da7b41d571e414cf92e4423cae1404a0

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 24baf8f1ce6223a99315b58edd12130af04b7a6969ec648095dfd48ab814c389
MD5 1e7509daf053c7e7a6f4879a26312d2e
BLAKE2b-256 f34c09a698dbb10679e4c4b7a2e3a0f3088cbcb68ed4898bc27d2b0c1ee17e6c

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e626a895ac80250184def9857f3f23980c12a7045f3d56b264b02a9746d16fda
MD5 7221f5afa62e318accd9305a08441cb5
BLAKE2b-256 981d3f988290c94c86a221537f15d7bc52f41fa86f8d791ac594922e0940dd75

See more details on using hashes here.

File details

Details for the file djangofmt-0.2.0-py3-none-linux_armv6l.whl.

File metadata

File hashes

Hashes for djangofmt-0.2.0-py3-none-linux_armv6l.whl
Algorithm Hash digest
SHA256 bf3a505fcf83e35de626bc48c7be3f1ff98078c477210a11879d5aca83c74199
MD5 373556eb079ae714b8d72122c4c7f013
BLAKE2b-256 69cb260dd70082d8bb9a409855e27bfa9a1dda41857e1c42d64ce4304e4ddea8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page