{"id":16177891,"url":"https://github.com/adamchainz/djade","last_synced_at":"2025-04-14T06:50:02.425Z","repository":{"id":257789805,"uuid":"860434541","full_name":"adamchainz/djade","owner":"adamchainz","description":"A Django template formatter.","archived":false,"fork":false,"pushed_at":"2025-04-07T18:09:12.000Z","size":161,"stargazers_count":321,"open_issues_count":13,"forks_count":5,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-11T14:33:43.466Z","etag":null,"topics":["django"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adamchainz.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":["https://adamj.eu/books/"]}},"created_at":"2024-09-20T12:32:38.000Z","updated_at":"2025-04-10T22:26:02.000Z","dependencies_parsed_at":"2024-10-10T05:20:41.077Z","dependency_job_id":"be9633c5-3755-464e-bd8c-98140eca01fb","html_url":"https://github.com/adamchainz/djade","commit_stats":{"total_commits":93,"total_committers":5,"mean_commits":18.6,"dds":"0.053763440860215006","last_synced_commit":"db1dda0ccd6abe4b7fdd01332cea89f0a1b23d4b"},"previous_names":["adamchainz/djade"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamchainz%2Fdjade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adamchainz","download_url":"https://codeload.github.com/adamchainz/djade/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248837274,"owners_count":21169373,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django"],"created_at":"2024-10-10T05:11:07.988Z","updated_at":"2025-04-14T06:50:02.394Z","avatar_url":"https://github.com/adamchainz.png","language":"Rust","funding_links":["https://adamj.eu/books/"],"categories":["Rust"],"sub_categories":[],"readme":"=====\nDjade\n=====\n\n.. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/djade/main.yml.svg?branch=main\u0026style=for-the-badge\n   :target: https://github.com/adamchainz/djade/actions?workflow=CI\n\n.. image:: https://img.shields.io/pypi/v/djade.svg?style=for-the-badge\n   :target: https://pypi.org/project/djade/\n\n.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white\u0026style=for-the-badge\n   :target: https://github.com/pre-commit/pre-commit\n   :alt: pre-commit\n\n.. figure:: https://raw.githubusercontent.com/adamchainz/djade/main/logo.svg\n   :alt: You can have any colour you like, as long as it’s jade.\n\n..\n\nA Django template formatter.\n\n    You can have any colour you like, as long as it’s [d]jade.\n\nDjade formats Django template syntax with a style based on the `template style guide \u003chttps://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/#template-style\u003e`__ in Django’s documentation.\nIt does not format HTML or other templated languages.\n\nDjade is fast because it is built in Rust: benchmarked taking 20ms to format 377 templates.\n\nRead more in `the introductory post \u003chttps://adamj.eu/tech/2024/09/26/django-introducing-djade/\u003e`__, or below.\n\n----\n\n**Improve your Django and Git skills** with `my books \u003chttps://adamj.eu/books/\u003e`__.\n\n----\n\nInstallation\n============\n\nUse **pip**:\n\n.. code-block:: sh\n\n    python -m pip install djade\n\nPython 3.9 to 3.13 supported.\n\npre-commit hook\n---------------\n\nYou can also install Djade as a `pre-commit \u003chttps://pre-commit.com/\u003e`__ hook.\n\n**First,** add the following to the ``repos`` section of your ``.pre-commit-config.yaml`` file (`docs \u003chttps://pre-commit.com/#plugins\u003e`__):\n\n.. code-block:: yaml\n\n    -   repo: https://github.com/adamchainz/djade-pre-commit\n        rev: \"\"  # Replace with the latest tag on GitHub\n        hooks:\n        -   id: djade\n            args: [--target-version, \"5.2\"]  # Replace with Django version\n\nThe separate repository enables installation without compiling the Rust code.\n\nThe default configuration uses pre-commit’s |files option|__ to pick up all text files in directories called ``templates`` (`source \u003chttps://github.com/adamchainz/djade-pre-commit/blob/main/.pre-commit-hooks.yaml\u003e`__).\nYou 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.\n\n.. |files option| replace:: ``files`` option\n__ https://pre-commit.com/#creating-new-hooks\n\n**Second,** format your entire project:\n\n.. code-block:: sh\n\n    pre-commit run djade --all-files\n\nCheck these changes for any potential Djade bugs and commit them.\nTry ``git diff --ignore-all-space`` to check non-whitespace changes.\n\n**Third,** consider adding the previous commit SHA to a |.git-blame-ignore-revs file|__.\nThis will prevent the initial formatting commit from showing up in ``git blame``.\n\n.. |.git-blame-ignore-revs file| replace:: ``.git-blame-ignore-revs`` file\n__ https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view\n\nKeep the hook installed to continue formatting your templates.\npre-commit’s ``autoupdate`` command will upgrade Djade so you can take advantage of future features.\n\nUsage\n=====\n\n``djade`` is a command line tool that rewrites files in place.\nPass a list of template files to format them:\n\n.. code-block:: console\n\n    $ djade --target-version 5.2 templates/engine.html\n    1 file reformatted\n\nDjade can also upgrade some old template syntax.\nAdd the ``--target-version`` option with your Django version as ``\u003cmajor\u003e.\u003cminor\u003e`` to enable applicable fixers:\n\n.. code-block:: console\n\n    $ djade --target-version 5.2 templates/engine.html\n    1 file reformatted\n\nDjade does not have any ability to recurse through directories.\nUse the pre-commit integration, globbing, or another technique to apply it to many files.\nFor example, |with git ls-files pipe xargs|_:\n\n.. |with git ls-files pipe xargs| replace:: with ``git ls-files | xargs``\n.. _with git ls-files pipe xargs: https://adamj.eu/tech/2022/03/09/how-to-run-a-command-on-many-files-in-your-git-repository/\n\n.. code-block:: sh\n\n    git ls-files -z -- '*.html' | xargs -0r djade\n\n…or PowerShell’s |ForEach-Object|__:\n\n.. |ForEach-Object| replace:: ``ForEach-Object``\n__ https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object\n\n.. code-block:: powershell\n\n    git ls-files -- '*.html' | %{djade $_}\n\nOptions\n=======\n\n``--target-version``\n--------------------\n\nOptional: the version of Django to target, in the format ``\u003cmajor\u003e.\u003cminor\u003e``.\nIf provided, Djade enables its fixers for versions up to and including the target version.\nSee the list of available versions with ``djade  --help``.\n\n``--check``\n-----------\n\nAvoid writing any formatted files back.\nInstead, exit with a non-zero status code if any files would have been modified, and zero otherwise.\n\nFormatting\n==========\n\nDjade aims to format Django template syntax in a consistent, clean way.\nIt wants to be like `Black \u003chttps://black.readthedocs.io/en/stable/\u003e`__: opinionated and free of configuration.\nDjade’s style is based on the rules listed in the Django contribution style guide’s `template style section \u003chttps://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/#template-style\u003e`__, plus some more.\n\nDjade does not aim to format the host language of templates (HTML, etc.).\nThat is a much broader scope and hard to do without semantic changes.\nFor example, whitespace is significant in some HTML contexts, such as in ``\u003cpre\u003e`` tags, so even adjusting indentation can affect the meaning.\n\nBelow are the rules that Djade implements.\n\nRules from the Django style guide:\n\n* Single spaces at the start and end of variables and tags:\n\n  .. code-block:: diff\n\n    -{{train}}\n    +{{ train }}\n\n    -{%  blow whistle  %}\n    +{% blow whistle %}\n\n* Label ``{% endblock %}`` tags that aren’t on the same line as their opening ``{% block %}`` tag:\n\n  .. code-block:: diff\n\n     {% block funnel %}\n     ...\n    -{% endblock %}\n    +{% endblock funnel %}\n\n* Sort libraries in ``{% load %}`` tags:\n\n  .. code-block:: diff\n\n    -{% load coal boiler %}\n    +{% load boiler coal %}\n\n* Inside variables, no spaces around filters:\n\n  .. code-block:: diff\n\n    -{{ fire | stoke }}\n    +{{ fire|stoke }}\n\n* Inside tags, single spaces between tokens:\n\n  .. code-block:: diff\n\n    -{% if  locomotive  ==  'steam engine'  %}\n    +{% if locomotive == 'steam engine' %}\n\n* Unindent top-level ``{% block %}`` and ``{% endblock %}`` tags when ``{% extends %}`` is used:\n\n  .. code-block:: diff\n\n    -  {% extends 'engine.html' %}\n    +{% extends 'engine.html' %}\n\n    -  {% block boiler %}\n    +{% block boiler %}\n       ...\n    -  {% endblock boiler %}\n    +{% endblock boiler %}\n\nExtra rules:\n\n* No leading empty lines:\n\n  .. code-block:: diff\n\n    -\n     {% extends 'engine.html' %}\n     ...\n\n* No trailing empty lines:\n\n  .. code-block:: diff\n\n     ...\n     {% endblock wheels %}\n    -\n    -\n\n* Single spaces at the start and end of comments:\n\n  .. code-block:: diff\n\n    -{#choo choo#}\n    +{# choo choo #}\n\n* No labels in ``{% endblock %}`` tags on the same line as their opening ``{% block %}`` tag:\n\n  .. code-block:: diff\n\n    -{% block funnel %}...{% endblock funnel %}\n    +{% block funnel %}...{% endblock %}\n\n* Merge consecutive ``{% load %}`` tags:\n\n  .. code-block:: diff\n\n    -{% load boiler %}\n    -\n    -{% load coal %}\n    +{% load boiler coal %}\n\n* Sort loaded items in ``{% load ... from .. %}`` tags:\n\n.. code-block:: diff\n\n    -{% load steam heat from boiler %}\n    +{% load heat steam from boiler %}\n\n* Unindent ``{% extends %}`` tags:\n\n  .. code-block:: diff\n\n    -  {% extends 'engine.html' %}\n    +{% extends 'engine.html' %}\n\n* Exactly one blank line between top-level ``{% block %}`` and ``{% endblock %}`` tags when ``{% extends %}`` is used:\n\n.. code-block:: diff\n\n     {% extends 'engine.html' %}\n\n    -\n     {% block funnel %}\n       ...\n     {% endblock funnel %}\n    +\n     {% block boiler %}\n       ...\n     {% endblock boiler %}\n\nFixers\n======\n\nDjade applies the below fixes based on the target Django version from ``--target-version``.\n\nDjango 4.2+: ``length_is`` -\u003e ``length``\n----------------------------------------\n\nFrom the `release note \u003chttps://docs.djangoproject.com/en/4.2/releases/4.2/#id1\u003e`__:\n\n    The ``length_is`` template filter is deprecated in favor of ``length`` and the ``==`` operator within an ``{% if %}`` tag.\n\nDjade updates usage of the deprecated filter within ``if`` tags, without other conditions, appropriately:\n\n.. code-block:: diff\n\n    -{% if engines|length_is:1 %}\n    +{% if engines|length == 1 %}\n\nDjango 4.1+: empty ID ``json_script`` fixer\n-------------------------------------------\n\nFrom the `release note \u003chttps://docs.djangoproject.com/en/4.1/releases/4.1/#templates\u003e`__:\n\n    The HTML ``\u003cscript\u003e`` element ``id`` attribute is no longer required when wrapping the ``json_script`` template filter.\n\nDjade removes the argument where ``json_script`` is passed an empty string, to avoid emitting ``id=\"\"``:\n\n.. code-block:: diff\n\n    -{% tracks|json_script:\"\" %}\n    +{% tracks|json_script %}\n\nDjango 3.1+: ``trans`` -\u003e ``translate``, ``blocktrans`` / ``endblocktrans`` -\u003e ``blocktranslate`` / ``endblocktranslate``\n-------------------------------------------------------------------------------------------------------------------------\n\nFrom the `release note \u003chttps://docs.djangoproject.com/en/3.1/releases/3.1/#templates\u003e`__:\n\n    The renamed ``translate`` and ``blocktranslate`` template tags are introduced for internationalization in template code.\n    The older ``trans`` and ``blocktrans`` template tags aliases continue to work, and will be retained for the foreseeable future.\n\nDjade updates the deprecated tags appropriately:\n\n.. code-block:: diff\n\n    -{% load blocktrans trans from i18n %}\n    +{% load blocktranslate translate from i18n %}\n\n    -{% trans \"Engine colours\" %}\n    +{% translate \"Engine colours\" %}\n\n    -{% blocktrans with colour=engine.colour %}\n    +{% blocktranslate with colour=engine.colour %}\n     This engine is {{ colour }}.\n    -{% endblocktrans %}\n    +{% endblocktranslate %}\n\nDjango 3.1+: ``ifequal`` and ``ifnotequal`` -\u003e ``if``\n-----------------------------------------------------\n\nFrom the `release note \u003chttps://docs.djangoproject.com/en/3.1/releases/3.1/#id2:~:text=The%20%7B%25%20ifequal%20%25%7D%20and%20%7B%25%20ifnotequal%20%25%7D%20template%20tags\u003e`__:\n\n    The ``{% ifequal %}`` and ``{% ifnotequal %}`` template tags are deprecated in favor of ``{% if %}``.\n\nDjade updates the deprecated tags appropriately:\n\n.. code-block:: diff\n\n    -{% ifequal engine.colour 'blue' %}\n    +{% if engine.colour == 'blue' %}\n     Thomas!\n    -{% endifequal %}\n    +{% endif %}\n\n    -{% ifnotequal engine.colour 'blue' %}\n    +{% if engine.colour != 'blue' %}\n     Not Thomas.\n    -{% endifnotequal %}\n    +{% endif %}\n\nDjango 2.1+: ``admin_static`` and ``staticfiles`` -\u003e ``static``\n---------------------------------------------------------------\n\nFrom the `release note \u003chttps://docs.djangoproject.com/en/2.1/releases/2.1/#features-deprecated-in-2-1\u003e`__:\n\n    ``{% load staticfiles %}`` and ``{% load admin_static %}`` are deprecated in favor of ``{% load static %}``, which works the same.\n\nDjade updates ``{% load %}`` tags appropriately:\n\n.. code-block:: diff\n\n    -{% load staticfiles %}\n    +{% load static %}\n\n    -{% load admin_static %}\n    +{% load static %}\n\nDjango 1.3+: legacy variable assignment syntax\n----------------------------------------------\n\nThe minimum target Django version is 2.1, so this fixer is always active.\n\nDjango 1.3 added support for ``=`` to assign variables in ``{% with %}`` and ``{% blocktranslate %}`` tags.\nPrior to this, they only supported the legacy syntax using the ``as`` keyword, which Django still supports.\n\nDjade rewrites the older ``as`` syntax to the newer ``=`` one:\n\n.. code-block:: diff\n\n    -{% with engines.count as total %}\n    +{% with total=engines.count %}\n         ...\n     {% endwith %}\n\n    -{% blocktranslate with engine.colour as colour %}\n    +{% blocktranslate with colour=engine.colour %}\n         ...\n     {% endblocktranslate %}\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamchainz%2Fdjade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadamchainz%2Fdjade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamchainz%2Fdjade/lists"}