plain-cache changelog
0.32.0 (2026-09-21)
What's changed
- Requires Python 3.14 (3f1590d33b)
Upgrade instructions
- Requires plain.postgres 0.121.0.
- Requires Python 3.14 — see the plain 0.165.0 upgrade instructions.
0.31.3 (2026-09-21)
What's changed
- The cache queries and the
live()/expired()/unexpired()/forever()queryset methods use typedwhere()conditions; SQL is unchanged (8f4a537f1f)
Upgrade instructions
- No changes required.
0.31.2 (2026-09-20)
What's changed
set_many()writes throughbulk_upsert()instead ofbulk_create(update_conflicts=True)— same single statement, andupdated_atis refreshed on the conflict path by the ORM rather than by hand (1132f46346)CachedItemuses the typedField[T]annotations from plain-postgres 0.119;valueis typedobject(any JSON-serializable value) (acae922618) (f37ab1014b)
Upgrade instructions
- Requires plain-postgres 0.119.0 or newer, which this release pins.
0.31.1 (2026-08-12)
What's changed
- Admin viewset attributes declared as tuples; internal lint cleanups (f52e18f532)
Upgrade instructions
- No changes required.
0.31.0 (2026-06-22)
What's changed
- Collapsed the migration history into a single fresh
0001_initial. The database schema is unchanged — only the migration files were squashed. (802f2d87)
Upgrade instructions
- Run
plain migrations pruneafter upgrading to clear the now-orphaned history records for this package's old migrations. No SQL runs — it only cleans up migration-history records and is safe and idempotent. Ifmigrations pruneis already part of your deploy steps, no action is needed.
0.30.0 (2026-06-07)
What's changed
New
increment(key, delta=1, *, expiration=None)anddecrement(key, delta=1, *, expiration=None)— atomically adjust a stored number in a singleINSERT ... ON CONFLICTstatement and return the new total. Because it's one statement, concurrent callers can't lose updates the way a read-then-set()would, making it the right primitive for counters and fixed-window rate limiters. A missing key (or one storingNone) counts as0, so the first increment starts fromdelta; a non-numeric stored value raises. (99a5d1f6a1)Expiry follows a fixed-window rule: a missing or expired key starts fresh at
deltaand takes theexpirationyou pass, while a live key adds to the existing total and keeps its currentexpires_at(regardless of theexpirationargument). To slide the TTL on each call instead, follow up withtouch().Removed
cache.exists(). A singleget()answers presence and returns the value in one query, so check it directly:if cache.get("k") is not None:. IfNoneis a value you legitimately store, pass a sentinel default to tell "absent" from a storedNone. (6ff26a98c8)
Upgrade instructions
- Replace
cache.exists("key")withcache.get("key") is not None. If you storeNoneas a real value, use a sentinel:missing = object(); cache.get("key", missing) is not missing. To compute-and-store on a miss, preferget_or_set()over a check-then-set.
0.29.0 (2026-06-07)
What's changed
plain.cacheis redesigned around a stateless, module-levelcachesingleton. TheCached(key)class is gone; importcacheand pass the key per call. (ab0f4b876f)| Before | After | | ----------------------------------- | ---------------------------------- | |
Cached("k").set(v, expiration=60)|cache.set("k", v, expiration=60)| |Cached("k").value|cache.get("k")| |Cached("k").exists()|cache.exists("k")| |Cached("k").delete()|cache.delete("k")|get()replaces the.valueproperty and takes an optional default —cache.get("k", default)returns the default on a miss or expiry (instead of alwaysNone).set()is nowcache.set(key, value, *, expiration=...)—expirationis keyword-only, andset()returnsNone(it previously returned the stored value). It still rewrites the whole entry, including its expiry.New
get_or_set(key, default, *, expiration=None)— returns the cached value, or computes/stores/returns it on a miss.defaultmay be a value or a zero-arg callable (invoked only on a miss). A storedNonecounts as a hit.New batch methods —
get_many(keys)(a single query, returns only live entries),set_many(mapping, *, expiration=None), anddelete_many(keys).New
touch(key, *, expiration=None)— change a live entry's expiration without rewriting its value. It writes onlyexpires_at/updated_at, reusing the existing TOAST pointer, so refreshing the TTL of a multi-megabyte value doesn't re-TOAST the blob. ReturnsTrueif a live entry was updated,Falsefor a missing/expired key. Ideal for sliding-TTL caches of large values.New
clear()— delete every entry; returns the number of rows deleted. (delete()returns a bool;delete_many()andclear()return counts.)New
CachedItem.query.live()queryset method — the never-expiring-or-not-yet-expired filter that reads now use, so an entry past itsexpires_atreads as absent.expired()/unexpired()/forever()are unchanged; noteunexpired()still matches only rows with a future expiry (excluding forever rows), whereaslive()includes them.Stricter
expirationvalidation — aboolor a baredatepassed asexpirationnow raisesTypeErrorinstead of being silently treated as "never expires."
Upgrade instructions
- Replace
Cached("key")with thecachesingleton (see the table above):from plain.cache import cache, thencache.get("key")/cache.set("key", value, expiration=...)/cache.exists("key")/cache.delete("key"). expirationis now keyword-only onset()— usecache.set("k", v, expiration=60), not a positional third argument.- If you read
Cached(...).value, switch tocache.get(key)(pass a default if you don't wantNone). - If you relied on
set()returning the stored value, note it now returnsNone. - No migration required — the
CachedItemmodel is unchanged.
0.28.2 (2026-06-03)
What's changed
- A raced unique-key conflict during
set()now surfaces as aValidationError(mapped at the save boundary inplain.postgres), so the retry path catches(psycopg.IntegrityError, ValidationError)rather thanIntegrityErroralone. (40c97521c5)
Upgrade instructions
- No changes required. Requires
plain.postgres>=0.106.0.
0.28.1 (2026-05-25)
What's changed
- Internal: model field declarations updated for plain.postgres's new parameterized-descriptor field typing. (229ecdbbfa)
Upgrade instructions
- No changes required.
0.28.0 (2026-05-06)
What's changed
- Tighter autovacuum on
plaincache_cacheditemby default. The cache table is a high-churn workload — everyset()rewrites a row, and TOAST'd values leave orphaned chunks behind — so Plain now declares per-table storage parameters via the newplain-postgresstorage_parametersAPI:autovacuum_vacuum_scale_factor=0.1(heap) andtoast.autovacuum_vacuum_scale_factor=0.05(TOAST), down from Postgres' default of0.2. Both are exposed as the newCACHE_AUTOVACUUM_SCALE_FACTORandCACHE_TOAST_AUTOVACUUM_SCALE_FACTORsettings (overridable viaPLAIN_CACHE_*env vars). Convergence applies them on the nextplain postgres sync. (7fe40f72)
Upgrade instructions
- Requires
plain-postgres>=0.103.0. Runplain postgres syncafter upgrading to apply the new autovacuum storage parameters toplaincache_cacheditem.
0.27.5 (2026-05-05)
What's changed
- Exposes
__version__fromimportlib.metadataonplain.cachefor version probes that don't want to scrape pip metadata. (c6cf6edb)
Upgrade instructions
- No changes required.
0.27.4 (2026-04-17)
What's changed
- Updated
CachedItem.created_atandCachedItem.updated_atto the newcreate_now/update_nowkwargs for plain-postgres 0.96.0. (5d145e4, a44e5ec)
Upgrade instructions
- Requires
plain-postgres>=0.96.0. Runplain postgres syncafter upgrading to reconcile column defaults.
0.27.3 (2026-04-14)
What's changed
- Updated
clear-expiredandclear-allCLI commands and theClearExpiredchore to use the newQuerySet.delete()return type (anintdirectly instead of a(count, by_label)tuple) from plain-postgres 0.95.0. (29e10dba51d9) - Added explicit
plain.postgres>=0.95.0dependency — the package has always importedplain.postgresAPIs but previously relied on it being present transitively.
Upgrade instructions
- Requires
plain-postgres>=0.95.0.
0.27.2 (2026-04-05)
What's changed
- Removed OTel span instrumentation from cache operations. Cache operations (
get,set,delete,exists) no longer create their own OTel spans. The underlying postgres queries already producedb.*spans automatically, making the cache-level spans redundant noise. (b56a9edc9c7d)
Upgrade instructions
- No changes required.
0.27.1 (2026-03-29)
What's changed
- Removed
AddIndexandRenameIndexoperations from migrations — indexes are now managed by convergence. (c58b4ba1fec9) - Updated docs to reference
plain postgres syncinstead ofplain migrate. (b026895edc4c)
Upgrade instructions
- No changes required.
0.27.0 (2026-03-28)
What's changed
- Replaced
CharFieldwithTextFieldin models and migration files to match plain-postgres 0.90.0 (5062ee4dd1fd)
Upgrade instructions
- Requires
plain-postgres>=0.90.0 - Replace
CharFieldwithTextFieldin migration files that reference this package's models
0.26.3 (2026-03-27)
What's changed
- Changed
cache clear-allconfirmation flag from--forceto--yes/-yfor consistency across all CLI commands (0af36e101f03)
Upgrade instructions
- If you use
plain cache clear-all --forcein scripts, change it toplain cache clear-all --yes.
0.26.2 (2026-03-25)
What's changed
- Renamed indexes to use readable
{table}_{column}_idxnaming convention, replacing the old truncated hash-based names. Includes a migration withRenameIndexoperations (instantALTER INDEX RENAME, no locks). (74aa8b76aa40)
Upgrade instructions
- Run
plain migrateto apply the index rename migration. This is an instant metadata-only operation with no performance impact.
0.26.1 (2026-03-22)
What's changed
- Switched from
plain.postgres.IntegrityErrortopsycopg.IntegrityErrordirectly (d4b170e60a2c)
Upgrade instructions
- No changes required.
0.26.0 (2026-03-12)
What's changed
- Updated all imports from
plain.modelstoplain.postgresin admin, core, models, and migrations.
Upgrade instructions
- Update imports:
from plain.modelstofrom plain.postgres,from plain import modelstofrom plain import postgres.
0.25.4 (2026-02-26)
What's changed
- Removed redundant
allow_global_search = Falsefrom cache admin views — this is now the default in plain-admin (05d6fa2764)
Upgrade instructions
- No changes required.
0.25.3 (2026-02-26)
What's changed
- Auto-formatted config files with updated linter configuration (028bb95c3ae3)
Upgrade instructions
- No changes required.
0.25.2 (2026-02-04)
What's changed
- Added
__all__exports tomodelsmodule for explicit public API boundaries (f26a63a5c941)
Upgrade instructions
- No changes required.
0.25.1 (2026-01-28)
What's changed
- Updated admin views to use the new
get_initial_querysethook instead ofget_objects(99d6f042b8)
Upgrade instructions
- If you have customized the cache admin views, rename
get_objects()toget_initial_queryset().
0.25.0 (2026-01-15)
What's changed
- Admin interface updated with new "database" icon and added description for cached items list view (0fc4dd3)
Upgrade instructions
- No changes required
0.24.0 (2026-01-13)
What's changed
- Expanded README documentation with comprehensive usage examples, FAQs, and improved structure (da37a78)
Upgrade instructions
- No changes required
0.23.0 (2025-11-24)
What's changed
- Removed unused type ignore comment for improved code cleanliness (bfb851f)
Upgrade instructions
- No changes required
0.22.1 (2025-11-17)
What's changed
- QuerySet manager type annotation updated from
ClassVarto standard annotation for improved type checker compatibility (1c624ff)
Upgrade instructions
- No changes required
0.22.0 (2025-11-13)
What's changed
- QuerySet manager now uses
ClassVartype annotation for improved type checking (c3b00a6)
Upgrade instructions
- No changes required
0.21.0 (2025-11-13)
What's changed
- Model field definitions now use type stub syntax with
plain.models.typesfor improved type checking and IDE support (c8f40fc)
Upgrade instructions
- No changes required
0.20.2 (2025-11-03)
What's changed
- CLI commands now include descriptive docstrings for improved help text (fdb9e80)
Upgrade instructions
- No changes required
0.20.1 (2025-10-31)
What's changed
- Added BSD-3-Clause license metadata to package configuration (8477355)
Upgrade instructions
- No changes required
0.20.0 (2025-10-17)
What's changed
- Chores have been rewritten as abstract base classes instead of function-based decorators (c4466d3)
Upgrade instructions
- If you have custom chores defined, update them from function-based decorators to class-based chores that inherit from
Choreand implement arun()method (see plain.chores documentation)
0.19.0 (2025-10-07)
What's changed
- Model configuration updated from
class Metatomodel_optionsdescriptor for improved type safety (17a378d) - QuerySet is now a proper descriptor with enhanced type annotations (2578301)
- Improved type safety by removing
type: ignorecomments throughout the package (73ba469)
Upgrade instructions
- No changes required
0.18.1 (2025-10-06)
What's changed
- Added comprehensive type annotations throughout the package, achieving 100% type coverage (154d4c4)
Upgrade instructions
- No changes required
0.18.0 (2025-09-12)
What's changed
- Model manager API has been updated from
.objectsto.query(037a239) - Minimum Python version requirement raised to 3.13 (d86e307)
Upgrade instructions
- Update any custom code that references
CachedItem.objectsto useCachedItem.queryinstead
0.17.2 (2025-08-22)
What's changed
- Updated README.md with improved documentation structure and formatting (4ebecd1)
- Admin interface icon positioning updated to be on nav sections (5a6479a)
Upgrade instructions
- No changes required
0.17.1 (2025-07-23)
What's changed
- Added archive icon to the cache admin interface navigation (9e9f8b0)
Upgrade instructions
- No changes required
0.17.0 (2025-07-22)
What's changed
- Database migrations updated to use new PrimaryKeyField instead of BigAutoField (4b8fa6a)
- Admin interface now uses
idinstead ofpkfor queryset ordering
Upgrade instructions
- No changes required
0.16.0 (2025-07-18)
What's changed
- Added OpenTelemetry tracing support for all cache operations (get, set, delete, exists) (b0224d0)
Upgrade instructions
- No changes required
0.15.0 (2025-07-18)
What's changed
- Database migrations have been restarted and consolidated into a single initial migration (484f1b6)
- Admin interface query optimization restored using
.only()to fetch minimal fields for list views
Upgrade instructions
- Run
plain migrate --prune plaincacheto handle the migration restart and remove old migration files
0.14.3 (2025-06-26)
What's changed
- No user-facing changes. This release only adds and formats the package CHANGELOG file (82710c3).
Upgrade instructions
- No changes required