Skip to content

Cache consistency

Enable raw-template caching only when repeated source reads justify another stateful dependency. With no CACHE section, resolution never initializes a Django cache backend.

The backend must provide atomic add() and coherent reads for generation barriers. Django's FileBasedCache and its subclasses are rejected with dj_hyperview.E018: their separate existence check and write can resurrect an invalidated template. Direct TemplateCache use raises SourceUnavailable with reason unsupported backend. FAILURE_MODE="bypass" does not override this configuration error.

Do not point CACHE.ALIAS at Django's DummyCache. That backend intentionally stores nothing and cannot satisfy generation or invalidation guarantees. Omit the CACHE section when caching should be disabled.

Opt in

Configure a normal Django cache alias and bind Hyperview to it:

CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
        "LOCATION": "hyperview-docs",
    },
}

HYPERVIEW = {
    "TEMPLATE_DIRS": [BASE_DIR / "hyperview"],
    "SOURCES": [{"BACKEND": "dj_hyperview.sources.FileSystemSource"}],
    "CACHE": {
        "ALIAS": "default",
        "NAMESPACE": "my-service-v1",
        "TTL": 300,
        "NEGATIVE_TTL": 15,
        "FAILURE_MODE": "bypass",
    },
}

The cache stores raw content and source misses, including valid empty content. It never stores compiled templates. Namespace, source identity, canonical name, revision, and generation keep entries isolated.

Select a Redis database

CACHE.ALIAS can point to a compatible stateful cache configured in Django. Redis host, credentials, logical database, and transport belong in CACHES; dj-hyperview only resolves the alias. LocMemCache provides atomic operations inside one process, but a multi-process deployment needs a shared backend such as Redis so every worker observes invalidations.

For example, dedicate Redis logical database 3 to Hyperview templates:

CACHES = {
    "hyperview": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/3",
    },
}

HYPERVIEW = {
    "CACHE": {
        "ALIAS": "hyperview",
        "NAMESPACE": "my-service-v1",
        "TTL": 300,
        "NEGATIVE_TTL": 15,
        "FAILURE_MODE": "bypass",
    },
}

Change the final URL segment to select another logical database supported by the configured Redis deployment. A separate alias may also point to another Redis server or cluster. Backend-specific restrictions still apply; the package does not bypass limitations imposed by Django's backend or Redis.

When upgrading from FileBasedCache, either remove the Hyperview CACHE section or configure a compatible backend before deployment. Use a fresh Hyperview namespace rather than copying old cache entries; do not clear a shared Django cache to migrate this package's entries.

bypass returns authoritative source data when ordinary cache reads or writes fail. raise reports SourceUnavailable instead. Neither mode hides a real source failure.

An explicitly bound DatabaseSource never publishes a source read while its database connection is inside a transaction. Existing cache hits remain available, but an older transaction snapshot cannot pin stale content under a newer generation. Applications using ATOMIC_REQUESTS therefore fall back to database reads for cache misses without sharing those snapshot-local results.

Invalidate after publication

Database services and model signals schedule invalidation after commit. For a custom publisher, rotate the generation only after its write commits:

from django.db import transaction

from dj_hyperview import invalidate_templates

transaction.on_commit(
    lambda: invalidate_templates("screens/home.xml"),
    using="default",
)

Invalidation is a shared fail-closed barrier even when reads use bypass. A multi-name call validates all names first, but rotations are not atomic; retry the whole requested set after a reported failure.

Unknown template misses create no cache metadata. The first successful lookup through a cacheable source creates one non-expiring generation key; later invalidations rotate that same key with a new random token. Raw content and negative entries remain bounded by their configured TTLs. If the generation key is externally evicted, the next successful source lookup establishes a fresh generation and old raw entries remain unreachable.

Invalidate after a filesystem deploy

A filesystem deploy does not invalidate already cached source content. In-place file changes and atomic root symlink swaps remain stale until their TTL expires. After every filesystem deploy, call invalidate_templates for the affected canonical names or rotate CACHE.NAMESPACE for the whole release. Namespace rotation is simpler for immutable deployments; targeted invalidation avoids a cold cache when only a few screens changed.