Skip to content

Home

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

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

Shows a bar chart with benchmark results.

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

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

  • ⚡️ 70-120x faster than existing Django template formatters
  • 🐍 Installable via pip, uv or pipx
  • 🛡️ A strict HTML aware parser: invalid HTML is reported as an error instead of being silently mangled
  • 🎨 Formats CSS in <style> tags and style attributes, and JSON in <script type="application/json">
  • 🔧 Lint rules with autofix, for automatic error correction (e.g., automatically sort Tailwind classes)
  • 🛠️ pyproject.toml and .editorconfig support
  • ⌨️ Editor integrations, a pre-commit hook and a browser playground

Table of contents

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

Usage

To run the formatter:

djangofmt .                    # Format all files in the current directory (and any subdirectories).
djangofmt src/templates        # Format all template files in `src/templates`
djangofmt templates/base.html  # Format individual files

When given a directory, djangofmt recurses into it and formats all *.html, *.jinja, *.jinja2, and *.j2 files it finds (respecting .gitignore files).

To run the linter:

djangofmt check .                       # Report violations
djangofmt check --fix .                 # Apply safe fixes, then report what is left
djangofmt check --fix --unsafe-fixes .  # Apply all fixes, unsafe ones included
  • See Running the linter for rule selection, fixes and suppression comments, or djangofmt check --help for the full list of options.
  • See Lint rules for the full list of available rules and categories.

Pre-commit hook

See pre-commit for instructions.

Sample .pre-commit-config.yaml:

- repo: https://github.com/UnknownPlatypus/djangofmt-pre-commit
  # Djangofmt version.
  rev: v1.0.0
  hooks:
    # Run the linter.
    - id: djangofmt-check
      args: [--fix]
    # Run the formatter.
    - 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.

.svg files support

djangofmt can format svg files too. There is a dedicated pre-commit hook for these:

- repo: https://github.com/UnknownPlatypus/djangofmt-pre-commit
  rev: v1.0.0
  hooks:
    - id: djangofmt-svg

Check mode

--check reports the files that would be reformatted without writing anything, exiting with 1 if any would change:

djangofmt --check .

CI is usually too late for a code formatter though: prefer the pre-commit hook above or an IDE "format on save" integration.

Configuration

Djangofmt can also be configured via a [tool.djangofmt] section in your pyproject.toml:

[tool.djangofmt]
line-length = 120
indent-width = 4
profile = "django"
custom-blocks = ["stage", "flatblock"]
html-void-self-closing = "never"
preserve-unquoted-attrs = false

Lint rules, used by the djangofmt check command, are configured in the nested [tool.djangofmt.lint] section:

[tool.djangofmt.lint]
select = ["category:all"]
ignore = ["category:style"]
preview = true
target-version = "5.2"
fix = true

[tool.djangofmt.lint.per-file-ignores]
"templates/admin/*.html" = ["missing-img-alt"]

target-version is the Django version your templates target. When unset, it comes from the minimum supported Django version in [project] dependencies. Rules that depend on it stay disabled until it is known.

Every option is documented in the settings reference.

Djangofmt looks for a pyproject.toml file by traversing directories upward from the current working directory. The first pyproject.toml found is used. If no file is found or the file doesn't contain a [tool.djangofmt] section, defaults are used.

Djangofmt also reads EditorConfig settings from the nearest .editorconfig file:

root = true

[*]
indent_size = 4
max_line_length = 120

Command-line arguments always take precedence over pyproject.toml settings, which take precedence over .editorconfig settings.

See Controlling the formatting for the behaviour of each option and how to opt into per-node overrides.

Editor integration

See the editor integration guide.

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]

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details on how to get started.