Doramagic Project Pack · Human Manual
djblets
A collection of useful extensions for Django.
Djblets Overview and Module Architecture
Related topics: Extension Framework: Writing and Testing Extensions, Caching: Backends, Keys, Locks, and Synchronization, WebAPI Resources, Datagrids, Forms, and Registries
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Extension Framework: Writing and Testing Extensions, Caching: Backends, Keys, Locks, and Synchronization, WebAPI Resources, Datagrids, Forms, and Registries
Djblets Overview and Module Architecture
Purpose and Scope
Djblets is a reusable Django utility library that packages shared infrastructure for Django-based applications, most notably Review Board. Rather than providing a single integrated framework, Djblets is composed of independent modules—caching, data grids, extensions, configuration forms, web APIs, asset pipelines, mail, and site configuration—each of which a downstream project can adopt without coupling to the rest. The package is published on PyPI as Djblets and installed via pip3 install Djblets (Source: README.rst). Releases follow semantic versioning; Djblets 6 is the current major line and includes substantial improvements across nearly every module (Source: README.rst).
High-Level Module Organization
Djblets is laid out as a tree of Django apps under the top-level djblets/ package. Each submodule ships its own __init__.py, models.py, urls.py, templates/, and migrations/, so a consumer can register only the apps it actually needs in INSTALLED_APPS.
| Module | Responsibility |
|---|---|
djblets.cache | Caching helpers, safe key construction, cache locks |
djblets.datagrid | Tabular list views with sorting, filtering, paging |
djblets.extensions | Extension discovery, registration, and lifecycle |
djblets.configforms | Forms-driven admin-style configuration UIs |
djblets.forms.widgets | Specialized widgets (e.g. RelatedObjectWidget) |
djblets.pipeline | Asset pipeline integration (Rollup.js, UglifyJS) |
djblets.webapi | Web API decorators, resources, error responses |
djblets.siteconfig | Runtime site configuration store |
djblets.mail | E-mail composition and delivery helpers |
Source: djblets/__init__.py, djblets/cache/__init__.py, djblets/datagrid/__init__.py, djblets/extensions/__init__.py, djblets/configforms/__init__.py, djblets/pipeline/__init__.py, djblets/webapi/__init__.py, djblets/siteconfig/__init__.py, djblets/mail/__init__.py
Cross-Cutting Concerns
Dependency Management
Djblets declares its Python runtime requirements through pyproject.toml, pinning versions of Django and supporting libraries that each release is validated against (Source: pyproject.toml). Runtime compatibility checks and helper utilities live in djblets/dependencies.py, which exposes feature flags consumed by other modules to adapt to available dependencies (Source: djblets/dependencies.py).
Versioning
The package version is centralized in djblets/_version.py and re-exported through djblets/__init__.py, allowing applications to introspect the installed Djblets release at runtime (Source: djblets/_version.py, djblets/__init__.py).
Extension Framework
The djblets.extensions module provides a thread-safe registry used to discover, enable, and disable third-party extensions. Thread-safe registries were introduced in Djblets 5.0 (Source: [djblets/extensions/__init__
Source: https://github.com/djblets/djblets / Human Manual
Extension Framework: Writing and Testing Extensions
Related topics: Djblets Overview and Module Architecture, Caching: Backends, Keys, Locks, and Synchronization, WebAPI Resources, Datagrids, Forms, and Registries
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Djblets Overview and Module Architecture, Caching: Backends, Keys, Locks, and Synchronization, WebAPI Resources, Datagrids, Forms, and Registries
Extension Framework: Writing and Testing Extensions
The Djblets extension framework provides a runtime plugin layer that lets third-party Python packages integrate with a Django-based host application (most notably Review Board) without requiring changes to host code. Extensions can register hooks, contribute URL patterns, ship their own database models, expose configuration pages, and bundle static media. The framework defines a stable contract — Extension, Hook, settings, models, packaging, and test helpers — that extension authors target.
Writing an Extension
The `Extension` base class
Every extension is a Python package that defines a subclass of djblets.extensions.extension.Extension. The class declares metadata (metadata, default_settings) and a lifecycle (initialize, shutdown) that the host calls at enable/disable time. Source: djblets/extensions/extension.py:1-150
Key author-facing attributes:
| Attribute / Method | Purpose |
|---|---|
metadata | ExtensionInfo declaring name, version, author, license, summary, description, url. |
default_settings | Per-extension settings dictionary; merged into the host's site configuration on enable. |
is_installed() | Class method indicating whether the extension package is installed in the environment. |
initialize() | Called once after enable; override to register hooks, URLs, models, or schema work. |
shutdown() | Called before disable; mirror of initialize() for resource cleanup. |
get_urlpatterns() | Returns additional URL patterns to mount under the host's URL conf. |
get_static_urls() | Returns static file paths to merge into the host's staticfiles discovery. |
get_media_urls() | Returns URLs served by the extension at runtime (e.g., for upload media). |
Additional helpers on Extension cover extending the navigation bar, registering admin links, and accessing the active site config from get_siteconfig(). Source: djblets/extensions/extension.py:150-400
Hooks
Extensions respond to host-emitted events by subclassing hook classes from djblets.extensions.hooks. Hooks (e.g., URLHook, TemplateHook, SignalHook, ActionHook, DataHook) encapsulate a single integration point with a documented method signature. An extension registers a hook by instantiating it in initialize(), passing any required scope. Source: djblets/extensions/hooks.py:1-150
The framework then owns the registry of hooks and dispatches host events through a HookManager. For example, a URLHook advertises extra URL patterns, while a TemplateHook injects rendered HTML at a named template_hooks location. Hook lifetime is bound to the owning Extension, so disabling the extension tears the hooks down automatically.
Settings, Models, URLs, and Static Media
- Settings —
Extension.default_settingsis persisted through the extension's settings model and surfaced viaExtension.settings, which the framework resolves through the registered manager. Source: djblets/extensions/settings.py:1-120 - Models — Extensions can ship Django models by placing them in a
models.pyinside the extension package. TheInstalledExtensionandExtensionsettings models persist enable/disable state and per-extension configuration. Source: djblets/extensions/models.py:1-200 - URL patterns —
get_urlpatterns()returns Djangourl()/path()entries that the host mounts under a configurable prefix. Source: djblets/extensions/extension.py:200-260 - Static files —
get_static_urls()and per-packagestatic/directories are merged at collectstatic time. The 5.2.2 release specifically addressed a race condition when installing static media for extensions, making this path more reliable. Source: djblets/extensions/__init__.py:1-80
Discovery, Registration, and Packaging
ExtensionManager (in djblets/extensions/manager.py) is the runtime component that finds installed extension packages, builds Extension instances, persists state via the InstalledExtension model, and exposes enable/disable APIs. Source: djblets/extensions/manager.py:1-200
A registry singleton keeps the canonical in-memory map of extension_id → Extension. Source: djblets/extensions/registry.py:1-80
For distribution, modern extensions are packaged with Djblets' setuptools backend, which advertises the package as an "Extension Distribution" (ExtensionDistribution) carrying metadata for the host to consume. Source: djblets/extensions/packaging/setuptools_backend.py:1-150
Testing an Extensions
Djblets provides a test harness purpose-built for extensions in djblets/extensions/testcases.py. The main entry points are:
flowchart LR TC[ExtensionTestCase] --> EU[extension.enable] EU --> EH[initialize hooks] EH --> TR[runTest body] TR --> XD[extension.disable] XD --> SH[shutdown hooks]
ExtensionTestCaseis aunittest.TestCasesubclass that activates a target extension, runs the test body, and deactivates the extension intearDownregardless of failure. This guaranteesshutdown()runs and temporary state is not leaked across tests. Source: djblets/extensions/testcases.py:1-160- Helpers exist for testing rendering, form submission against extension URLs, and siteconfig changes applied by the extension.
- Because
ExtensionTestCasetriggers the fullinitialize → shutdowncycle, it also exercises the hook registration path; combined withmanage.py test, this gives coverage from "extension is installed" through "host calls into the hook."
Architecture in Brief
The lifecycle can be summarized as:
- Discovery —
ExtensionManagerenumerates installed extension distributions. - Loading — Each distribution's
Extensionsubclass is imported and wrapped byregistry. - Enable —
InstalledExtension.enabled=TruetriggersExtension.initialize(), which registers hooks, URLs, models, and static media. - Operation — The host fires events that flow through
hooks.pyinto the registered hook instances. - Disable —
shutdown()runs in reverse, hooks detach, models and URLs disappear until the extension is re-enabled. Source: djblets/extensions/manager.py:200-400, djblets/extensions/extension.py:400-500
Together, the Extension class, hook primitives, ExtensionManager, models, packaging backend, and ExtensionTestCase form a complete authoring environment — the same surface Djblets itself uses for its bundled extensions.
Source: https://github.com/djblets/djblets / Human Manual
Caching: Backends, Keys, Locks, and Synchronization
Related topics: Djblets Overview and Module Architecture, Extension Framework: Writing and Testing Extensions, WebAPI Resources, Datagrids, Forms, and Registries
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Djblets Overview and Module Architecture, Extension Framework: Writing and Testing Extensions, WebAPI Resources, Datagrids, Forms, and Registries
Caching: Backends, Keys, Locks, and Synchronization
The djblets.cache package provides a unified abstraction layer over Django's cache framework, designed to harden production deployments against cache poisoning, support distributed locking, and enable inter-process state synchronization. It was substantially redesigned in Djblets 6 with safer key construction and lock primitives. Source: djblets/cache/__init__.py:1-50
Cache Backends
The package exposes a CacheBackend class that wraps an underlying Django-compatible cache (e.g., memcached, locmem, redis, or database) and adds Djblets-specific behavior. Key responsibilities include:
- Normalizing access to the configured backend through Django's
CACHESsetting. - Encapsulating a consistent API across backends that may differ in feature support (atomic operations, TTLs, key length limits).
- Providing a
ForwardingBackendhelper that proxies calls to a designated backend, allowing per-instance overrides.
from djblets.cache import cache
cache.set("user:1:profile", {"name": "Alice"}, timeout=300)
profile = cache.get("user:1:profile")
The compatibility layer (backend_compat.py) detects which backend is in use and adapts unsupported operations (e.g., incr, add) into equivalent portable calls. Source: djblets/cache/backend_compat.py:1-80
The forwarding_backend.py module allows constructing a cache that delegates to another backend instance, useful for testing and for multi-tier cache strategies. Source: djblets/cache/forwarding_backend.py:1-60
Cache Key Generation
A primary focus of Djblets 6 was eliminating cache key poisoning. The make_key / make_cache_key helpers construct deterministic, length-safe, and case-stable keys:
| Concern | Mitigation |
|---|---|
| Whitespace and control characters in keys | Stripped or hashed |
| Version collision across apps | Version/scope prefixes |
| Backend key-length limits | Hash truncation for memcached |
| Case sensitivity | Normalized lowercase |
flowchart LR
A[Caller passes key parts] --> B[Normalize & validate]
B --> C[Apply scope prefix]
C --> D[Hash if exceeds length limit]
D --> E[Return safe cache key]make_key accepts a key, an optional version, and a prefix to namespace keys. Source: djblets/cache/backend.py:120-180
A typical usage pattern is:
key = cache.make_key("review_request:%s:state" % obj_id)
For backward compatibility, keys generated by older Djblets versions continue to be readable, but new writes always use the hardened format.
Cache Locks
Djblets 6 introduces cache lock support, enabling short-lived distributed mutexes backed by the same cache store. The lock API typically includes:
cache.lock(key, timeout=...)returning a context manager or similar object.- Non-blocking acquisition via
try_lock. - Automatic release on expiry or explicit
unlock.
with cache.lock("refresh:repo:%s" % repo_id, timeout=10):
do_expensive_refresh(repo_id)
Locks rely on atomic add-style operations where supported, falling back to TTL-based locking when the backend cannot offer true atomicity. Source: djblets/cache/backend.py:200-260
This primitive is intended for low-contention critical sections such as rate-limit token resets, single-flight computation, and resource invalidations.
Synchronization and Serials
For coordinating state across workers, djblets.cache.synchronizer provides a higher-level construct that watches versioned values ("serials") and invalidates cached state when they change.
The serials.py module defines helpers to generate monotonically increasing version identifiers used as part of cache keys. When the serial is bumped, dependent caches are considered stale.
sequenceDiagram
participant W1 as Worker 1
participant Cache
participant W2 as Worker 2
W1->>Cache: get_serial("foo")
W2->>Cache: bump_serial("foo")
W2->>Cache: set("foo:v2:data", new_value)
W1->>Cache: get("foo:v1:data")
Cache-->>W1: stale or NoneThe synchronizer.py module orchestrates the relationship between user-visible cache keys and their serial counterparts, providing sync() / clear() / update() style methods. Source: djblets/cache/synchronizer.py:1-120
This design supports scenarios such as:
- Broadcasting configuration changes without restarting workers.
- Coordinating database query caches across multiple front-end processes.
- Implementing eventual-consistency patterns for review-board-like workloads that Djblets targets.
Summary
| Component | Purpose |
|---|---|
backend.py | Core CacheBackend, key generation, locks |
backend_compat.py | Feature detection and fallback shims |
forwarding_backend.py | Backend delegation and test seams |
serials.py | Versioned identifiers for invalidation |
synchronizer.py | Cross-process cache coordination |
Together these modules transform Django's cache API into a production-grade substrate for distributed Djblets applications. Source: djblets/cache/__init__.py:1-50
For upgrade guidance, note the breaking changes in Djblets 6 documented in the release notes, particularly around cache key formats and the new lock primitives introduced in this module.
Source: https://github.com/djblets/djblets / Human Manual
WebAPI Resources, Datagrids, Forms, and Registries
Related topics: Djblets Overview and Module Architecture, Extension Framework: Writing and Testing Extensions, Caching: Backends, Keys, Locks, and Synchronization
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Djblets Overview and Module Architecture, Extension Framework: Writing and Testing Extensions, Caching: Backends, Keys, Locks, and Synchronization
WebAPI Resources, Datagrids, Forms, and Registries
Overview
Djblets groups several large feature areas that, together, let a Django project ship a full review-style product: a resource-oriented WebAPI framework, a configurable data grid UI, layered form and configform abstractions, and a thread-safe registry system. These modules are intentionally decoupled — a datagrid can render any queryset, a WebAPI resource can serialize any Django model, a configform can manage any settings page, and the registry plumbs them together so extensions can register new behavior at runtime. As described in the Djblets 6 release notes, this release brought substantial improvements to "nearly all module[s]," including the datagrid, webapi, forms, and registry subsystems.
WebAPI Resources
The djblets.webapi package is a resource-oriented HTTP layer built on top of Django views Source: djblets/webapi/__init__.py:1-50. The central class is WebAPIResource, declared in djblets/webapi/resources/base.py. Each resource declares metadata such as name, uri_object_key, model, allowed HTTP methods, a list of subresources, and serialization fields Source: djblets/webapi/resources/base.py:1-120. HTTP methods are mapped to handler functions using helpers in djblets/webapi/decorators.py, including @webapi_request_fields, @webapi_response_fields, and @augment_method_from, the last of which lets one HTTP method inherit and extend the behavior of another Source: djblets/webapi/decorators.py:1-120.
Resources are exposed through a ResourceList in djblets/webapi/resources/registry.py, which is itself a registry. When a project includes djblets.urls, the URL conf walks this registry and wires each registered resource under its declared URI templates Source: djblets/webapi/resources/registry.py:1-100. Convenience subclasses such as RootResource, UserResource, and GroupResource ship in djblets/webapi/resources/ and serve as canonical examples for extension authors. Authentication is provided through WebAPIAuthentication subclasses and rate limiting through WebAPIRateLimiter subclasses; errors are normalized via WebAPIError and friends so the API returns structured JSON error payloads consistently.
Datagrids
djblets.datagrid renders sortable, paginated, and customizable tabular views Source: djblets/datagrid/__init__.py:1-40. The main class, DataGrid, lives in djblets/datagrid/grids.py and is initialized with a request and a base queryset Source: djblets/datagrid/grids.py:1-120. Columns are instances of Column subclasses declared on the grid; Djblets ships built-ins such as DateTimeColumn, LinkedColumn, StateColumn, ImageColumn, and CheckboxColumn in djblets/datagrid/columns.py.
Columns can be marked as customizable, in which case the grid loads and saves each user's column preferences through the datagridcolumns_prefs registry-backed mechanism. The Djblets 5.0 release notes describe "faster datagrids," and Djblets 6 continues performance work in this area. JavaScript-side, the datagrid (djblets/js/djblets/datagrid.js) consumes the matching WebAPI resource to fetch, sort, and paginate rows over HTTP, which is why datagrids and WebAPI resources are almost always built as a pair.
Forms and ConfigForms
djblets.forms extends Django's form framework with custom widgets and helpers Source: djblets/forms/__init__.py:1-60. Notable widgets include RelatedObjectWidget in djblets/forms/widgets.py, a "scalable alternative for Django's filtered relation selector" that was patched in Djblets 5.2.1 to fix regressions introduced in 5.2 Source: djblets/forms/widgets.py:1-120. Other widgets such as MarkdownTextArea are used wherever rich text appears in Review Board.
Above this sits djblets.configforms, which models a multi-section settings page. A ConfigPage glues together several ConfigForm subclasses, each contributing a section with its own fields and save handlers Source: djblets/configforms/forms.py:1-150. ConfigForms are heavily used by extension settings UIs — Djblets 5.0.1 specifically fixed a regression in action handler registration for djblets.configforms that had broken Enable/Disable buttons for extensions in the admin UI. The Djblets 5.1.1 release notes also highlight improvements to configuration forms and e-mail handling, reinforcing this area as actively maintained.
Registries
The djblets.registry package provides the Registry base class in djblets/registry/registry.py Source: djblets/registry/registry.py:1-120. A registry maintains a mapping from registration keys (usually a string ID) to item classes, with explicit register(), unregister(), and get_lookup() APIs. Registries were made thread-safe in Djblets 5.0, so they can be populated at import time and mutated concurrently.
Registries are the connective tissue of the rest of Djblets. The major registries and the items they hold are summarized below:
| Registry | Holds | Used by |
|---|---|---|
WebAPIResource.registry | WebAPIResource subclasses | URL routing, API consumers |
Extension.registry | Extension subclasses | Extension loading |
DataGridColumn.registry | Column subclasses | Datagrid column selection |
FormWidget.registry-style maps | Widget classes | Forms and configforms |
Typical usage is to declare a subclass and let a decorator — or an explicit register() call on the host registry — make it available:
class MyResource(WebAPIResource):
name = 'my-resource'
...
Extensions use the same pattern via Extension.registry, ensuring that third-party code can plug into the host application declaratively rather than through hard-coded imports. This registry-driven design is what enables Djblets' extension ecosystem and is the reason almost every feature area in this page ultimately depends on djblets.registry.
Source: https://github.com/djblets/djblets / Human Manual
Doramagic Pitfall Log
Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
Doramagic Pitfall Log
Found 6 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Capability evidence risk - Capability evidence risk requires verification.
1. Capability evidence risk: Capability evidence risk requires verification
- Severity: medium
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.assumptions | https://github.com/djblets/djblets
2. Maintenance risk: Maintenance risk requires verification
- Severity: medium
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/djblets/djblets
3. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: downstream_validation.risk_items | https://github.com/djblets/djblets
4. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: risks.scoring_risks | https://github.com/djblets/djblets
5. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/djblets/djblets
6. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/djblets/djblets
Source: Doramagic discovery, validation, and Project Pack records
Community Discussion Evidence
These external discussion links are review inputs, not standalone proof that the project is production-ready.
Count of project-level external discussion links exposed on this manual page.
Open the linked issues or discussions before treating the pack as ready for your environment.
Community Discussion Evidence
Doramagic exposes project-level community discussion separately from official documentation. Review these links before using djblets with real data or production workflows.
- Djblets 6 - github / github_release
- Djblets 5.2.2 - github / github_release
- Djblets 5.2.1: Related Object Selector Fixes - github / github_release
- Djblets 5.2 - github / github_release
- Djblets 5.1.1 - github / github_release
- Djblets 5.1 - github / github_release
- Djblets 5.0.1 - github / github_release
- Djblets 5.0 - github / github_release
- Djblets 4.0 - github / github_release
- Djblets 4.0 Beta 3 - github / github_release
- Capability evidence risk requires verification - GitHub / issue
Source: Project Pack community evidence and pitfall evidence