Conjunto
A Django framework for component-based, plugin-extendable web applications.
Conjunto bundles a curated, opinionated stack so you can build modern, interactive Django apps without wiring the same plumbing together every time:
- GDAPS — plugin architecture: drop-in apps extend the host through typed interfaces, auto-discovered at startup.
- Tabler.io (Bootstrap 5) — a complete, themeable admin/app UI kit (light & dark).
- HTMX — server-rendered interactivity without a SPA build step.
- django-tables2 + crispy-forms — declarative tables, filters and forms.
The result is a batteries-included foundation for multi-tenant, permission-aware line-of-business applications.
What's in the box
| Area | What you get |
|---|---|
| Plugins (GDAPS) | Extend menus, settings, tables, login and more via I… interfaces — no host code changes. |
| Layout | app_base.html (topbar, collapsible sidebar, statusbar, offcanvas) and a chrome-less base.html. Server-side theming avoids the dark-mode flash. |
| Menus | IMenuItem registry for topbar, sidebar (2 levels), user dropdown and footer — permission- and visibility-aware. |
| Scoped settings | Layered settings resolution USER > DEVICE > GROUP > TENANT > VENDOR with lockable floors; typed registry, DB-backed, request-cached. |
| Settings UI | Plugin-extendable settings page (ISettingsGroup / ISettingsSection / ISettingsForm) with HTMX save-in-place. |
| Tenants | Multi-tenancy: AbstractTenant, membership & runtime-editable roles, tenant-scoped model managers, and a tenant picker. |
| Tables & lists | TableListView with search, filters, row/header actions and HTMX modals — pluggable via IRowAction / IHeaderAction. |
| Forms | Smart TimeField/TimePickerInput, DatePickerInput, dependent-fields HTMX wiring, persistent file fields, safe-HTML fields. |
| Toasts & messages | Django messages surfaced as Tabler toasts on both full loads and HTMX swaps. |
| Audit log | log_action() + a pluggable action registry. |
| Dashboard widgets | Lazy-loading, reorderable (Gridstack) HTMX widgets with per-user layout. |
| Auth | Plugin-extendable login (ILoginMethod, ILoginViewExtension, IPostLoginAction), remember-me, two-step tenant pick. |
| Archive | Soft-delete + versioning + retention (no django-safedelete needed). |
| Wizard | Multi-step form wizard with session drafts. |
| Sortable lists | Fully HTMX-declarative drag-and-drop ordering for FK-linked models. |
| Profiles & avatars | Optional UserProfile with avatar, plus an always-available {% avatar %} tag. |
| Optional extras | Rendering (conjunto[htmx]), WebSockets (conjunto[realtime]), block CMS (conjunto[cms]), at-rest encryption (conjunto[crypto]). |
Requirements
- Python ≥ 3.12
- Django ≥ 6.0
Installation
pip install "conjunto[all]" # or: uv add "conjunto[all]"
Bare conjunto is the core layer — models, tenants, scoped settings — and pulls in nothing that renders. Pick the
extras you need instead:
pip install "conjunto[htmx]" # Django templates + HTMX + Tabler — every conjunto page needs this
pip install "conjunto[realtime]" # WebSockets (pulls in channels)
pip install "conjunto[cms]" # block CMS (pulls in django-polymorphic)
pip install "conjunto[crypto]" # at-rest field/file encryption (pulls in cryptography)
See Layering for what belongs to which layer.
Quick setup
1. Register the app. Add conjunto before django_extensions (it overrides the update_permissions command),
and add gdaps for plugin discovery:
INSTALLED_APPS = [
# ...
"conjunto",
"django_extensions",
"gdaps",
# optional: "conjunto.profiles", "conjunto.cms", ...
]
2. Add the middleware (order matters — TimezoneMiddleware after ConjuntoMiddleware; ConjuntoMessagesMiddleware
after Django's MessageMiddleware and after django_htmx's HtmxMiddleware):
MIDDLEWARE = [
# ...
"django.contrib.messages.middleware.MessageMiddleware",
"django_htmx.middleware.HtmxMiddleware",
"conjunto.middleware.ConjuntoMiddleware",
"conjunto.middleware.ConjuntoMessagesMiddleware",
"conjunto.middleware.TimezoneMiddleware",
]
3. Fetch the front-end libraries. Third-party JS/CSS (Tabler, HTMX, Alpine, TinyMCE, …) are not bundled in the wheel — download them into your project's static tree once:
python manage.py update_libraries --suggest # prints a CONJUNTO_LIBRARIES = [...] block
# paste it into settings.py, then:
python manage.py update_libraries # download the files
python manage.py update_libraries --check # CI guard (no network)
This keeps the wheel small (~1 MB instead of ~16 MB) and puts library versions under your control. See
docs/usage/static_libraries.md for CONJUNTO_VENDOR_DIR, STATICFILES_DIRS and CI
integration.
The installation guide covers the remaining settings (context processors, .env, layout).
Usage
Full documentation lives under docs/ — start with the layout,
menus, scoped settings and tenants guides.
Development
uv sync # install deps (dev group included)
uv run pytest # run the test suite
uv run pytest tests/test_x.py # run a single test module
uv run black . # format
uv build # build the wheel
Formatting is enforced with Black ≥ 25.12.0. Tests run against a bundled test app in tests/.
Contributing
Pull requests and ideas are welcome. For major changes, please open an issue first to discuss the direction.
License
Conjunto is open source under the MIT License. Note that it integrates many third-party libraries, which carry their
own (possibly different) licenses — see THIRD_PARTY_LICENSES.md.
Metadata
Release files for conjunto 0.20.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| conjunto-0.20.1.tar.gz | 5.7 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| conjunto-0.20.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 6.7 MB
Release files / conjunto-0.20.1.tar.gz
| Download URL | conjunto-0.20.1.tar.gz |
|---|---|
| Size | 5.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8de861798b359618506a986ef6b73dd5512892c24fc37d34217a78e4a702bbb9
|
|
BLAKE2b-256 checksum How to use checksums |
55afc307c4e380f4103c248acae812ce68f6bbf51f83054ba2366c2d079cb384
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / conjunto-0.20.1-py3-none-any.whl
| Download URL | conjunto-0.20.1-py3-none-any.whl |
|---|---|
| Size | 1.0 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b8fb8a22e7c530aa486cfbe72edc7d0f9b72fe584a9bec694c0c047de774ae5a
|
|
BLAKE2b-256 checksum How to use checksums |
8644e7c8763bfb2d3c6254041a4604531cfdff2fee2fa0f1134174c1cb92bd35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for conjunto 0.20.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.