Skip to content

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 23 Sep 17:34
· 342 commits to main since this release

djust 1.2 makes the Rust template engine behave like Django's, turns components into view state, and fixes eleven security advisories. djust 1.1.4, released the same day, carries the same security fixes for the 1.1 line.

Read the full release notes before upgrading: djust 1.2 release notes. They cover every incompatible change, what to do about each one, and an upgrade checklist.

Supports Python 3.10 to 3.14 and Django 4.2 (4.2.29 or later) to 5.2, the same range as 1.1.

Highlights

  • Django template compatibility. All 25 built-in tags and 57 built-in filters, {% load %} for your own tag libraries, {% translate %} / {% blocktranslate %}, and dotted lookups against the live Python object. 1032 of the 1047 Django template_tests that reach an engine pass (98.57%).
  • Faster renders with large state. Render cost now depends on what the template reads, not on everything the view holds.
  • Components are state. Class-level components bind per view and handle their own events (ADR-031). An event that changes one component patches only that component (ADR-032). Writing self.rating.value = 5 re-renders and survives a reconnect (ADR-033).
  • Component catalogue at /theme/components/, backed by describe_component().
  • djust init adds djust to an existing Django project. djust new generates a themed starter page.
  • Update and security notices from the CLI, the dev server and manage.py check (djust.U001).
  • @debounce / @throttle in the client, dj-mouseenter / dj-mouseleave, AudioMixin, LiveComponentTestClient, and djust replay for bug captures.

Backwards incompatible changes

Security hardening:

  • Built-in components HTML-escape their content. Mark slot HTML safe with mark_safe() or format_html().
  • djust admin enforces Django model permissions. Staff users who aren't superusers need view_/add_/change_/delete_ permissions.
  • The observability endpoints require the X-Djust-Observability-Token header. djust_mcp sends it; manage.py djust_observability_token prints it.
  • A custom tag that returns a plain string has its output escaped, and so does a custom filter registered with is_safe=True when its input wasn't safe. Return format_html() or mark_safe() for markup.
  • DataTable sorts, filters and groups only on declared columns. Filtering needs "filterable": True.
  • A LiveView joins its channel groups only after its permission checks pass.
  • Sticky {% live_render %} children are re-authorized on every parent render.
  • State snapshots from 1.1 are rejected once.
  • In-flight resumable uploads restart.
  • Theme cookies naming an unknown pack or layout fall back to the defaults.

Templates:

  • The errors Django raises are now raised too, many when the template is loaded: unknown filters and tags, _-prefixed names, wrong filter argument counts, and {% for %} over a non-iterable.
  • {% url %} raises NoReverseMatch; use as var where a failed reverse is expected.
  • Values render as in Django: datetimes in the current time zone, localized numbers, and True / None / [1, 2]. Set LIVEVIEW_CONFIG["django_value_repr"] = False to keep 1.1's rendering of plain values.

Runtime and client:

  • In-place mutations re-render.
  • A list[Model] isn't re-queried on every event.
  • The tick loop honours _skip_render.
  • URL kwargs arrive decoded.
  • Booleans reach the browser as true/false, Decimal values as strings, and datetimes in DjangoJSONEncoder format.

Components and theming:

  • self.nav is a BoundComponent; read its state from self.nav.state.
  • TableComponent.sort_by(column=...) and TabsComponent.activate_tab(tab=...) changed their arguments.
  • The modal backdrop is a .dj-scrim element.
  • The theme gallery moved to /theme/themes/ and the storybook to /theme/components/. The old paths redirect. Storybook* names became Components*.

Testing:

  • LiveViewTestClient.mount() takes the WebSocket branch by default; pass via_websocket=False for the prerender.
  • send_event() raises NoHandlerFoundError for an unknown handler.

Checks:

  • New T018, C016, V014 and U001 messages.
  • C013 fires until you run collectstatic.

Removed:

  • LIVEVIEW_CONFIG["template_resolve_lazy"] is gone.
  • The unused static files djust/security.js, djust/decorators.js and djust/js/pwa.js are no longer shipped.

Security

1.2.0 and 1.1.4 fix these advisories:

GHSA-3hp5-hxf8-qc48 (HTTP POST authorization) was fixed earlier, in 1.2.0rc8 and 1.1.3.

Upgrading from 1.1

  1. pip install "djust==1.2.0", then run python manage.py collectstatic.
  2. Run python manage.py check. Handle the new T018, C016, V014 and U001 messages. For templates that use {% extends %}, also run manage.py djust_typecheck.
  3. Run your tests. Add via_websocket=False to prerender tests, and expect NoHandlerFoundError for events that have no handler.
  4. Load every template once. djust now raises template errors that 1.1 ignored.
  5. Check rendered timestamps, numbers, {{ }} output and {% url %} calls.
  6. Mark component slot HTML safe, and make custom tags and filters that produce markup return safe strings.
  7. Grant model permissions to djust admin staff, and add "filterable": True to the DataTable columns you filter on.
  8. Update client JavaScript and CSS that reads booleans, decimals or datetimes, or targets the modal backdrop, data-value or data-row-id.
  9. Update links and imports for the theme gallery and component catalogue.

Full notes: docs/website/releases/1.2.md. Every change since 1.1: CHANGELOG, sections 1.2.0rc1 to 1.2.0 (1.2.0 is identical to 1.2.0rc11 apart from the version).

Every pull request since 1.1: compare v1.1.3...v1.2.0.