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

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Dependency Management

Continue reading this section for the full explanation and source context.

Section Versioning

Continue reading this section for the full explanation and source context.

Section Extension Framework

Continue reading this section for the full explanation and source context.

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.

ModuleResponsibility
djblets.cacheCaching helpers, safe key construction, cache locks
djblets.datagridTabular list views with sorting, filtering, paging
djblets.extensionsExtension discovery, registration, and lifecycle
djblets.configformsForms-driven admin-style configuration UIs
djblets.forms.widgetsSpecialized widgets (e.g. RelatedObjectWidget)
djblets.pipelineAsset pipeline integration (Rollup.js, UglifyJS)
djblets.webapiWeb API decorators, resources, error responses
djblets.siteconfigRuntime site configuration store
djblets.mailE-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

Section Related Pages

Continue reading this section for the full explanation and source context.

Section The Extension base class

Continue reading this section for the full explanation and source context.

Section Hooks

Continue reading this section for the full explanation and source context.

Section Settings, Models, URLs, and Static Media

Continue reading this section for the full explanation and source context.

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 / MethodPurpose
metadataExtensionInfo declaring name, version, author, license, summary, description, url.
default_settingsPer-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

  • SettingsExtension.default_settings is persisted through the extension's settings model and surfaced via Extension.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.py inside the extension package. The InstalledExtension and Extension settings models persist enable/disable state and per-extension configuration. Source: djblets/extensions/models.py:1-200
  • URL patternsget_urlpatterns() returns Django url()/path() entries that the host mounts under a configurable prefix. Source: djblets/extensions/extension.py:200-260
  • Static filesget_static_urls() and per-package static/ 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]
  • ExtensionTestCase is a unittest.TestCase subclass that activates a target extension, runs the test body, and deactivates the extension in tearDown regardless of failure. This guarantees shutdown() 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 ExtensionTestCase triggers the full initialize → shutdown cycle, it also exercises the hook registration path; combined with manage.py test, this gives coverage from "extension is installed" through "host calls into the hook."

Architecture in Brief

The lifecycle can be summarized as:

  1. DiscoveryExtensionManager enumerates installed extension distributions.
  2. Loading — Each distribution's Extension subclass is imported and wrapped by registry.
  3. EnableInstalledExtension.enabled=True triggers Extension.initialize(), which registers hooks, URLs, models, and static media.
  4. Operation — The host fires events that flow through hooks.py into the registered hook instances.
  5. Disableshutdown() 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

Section Related Pages

Continue reading this section for the full explanation and source context.

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 CACHES setting.
  • Encapsulating a consistent API across backends that may differ in feature support (atomic operations, TTLs, key length limits).
  • Providing a ForwardingBackend helper 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:

ConcernMitigation
Whitespace and control characters in keysStripped or hashed
Version collision across appsVersion/scope prefixes
Backend key-length limitsHash truncation for memcached
Case sensitivityNormalized 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 None

The 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

ComponentPurpose
backend.pyCore CacheBackend, key generation, locks
backend_compat.pyFeature detection and fallback shims
forwarding_backend.pyBackend delegation and test seams
serials.pyVersioned identifiers for invalidation
synchronizer.pyCross-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

Section Related Pages

Continue reading this section for the full explanation and source context.

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:

RegistryHoldsUsed by
WebAPIResource.registryWebAPIResource subclassesURL routing, API consumers
Extension.registryExtension subclassesExtension loading
DataGridColumn.registryColumn subclassesDatagrid column selection
FormWidget.registry-style mapsWidget classesForms 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.

medium Capability evidence risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Maintenance risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Security or permission risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Security or permission risk requires verification

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.

Sources 11

Count of project-level external discussion links exposed on this manual page.

Use Review before install

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.

Source: Project Pack community evidence and pitfall evidence