Skip to main content

A simple database-backed cache for storing JSON-serializable values with optional expiration.

Project description

plain.cache

A simple database-backed cache for storing JSON-serializable values with optional expiration.

Overview

You can store any JSON-serializable value in the cache using the Cached class. Each cached item is identified by a unique key and can optionally expire after a set amount of time.

from plain.cache import Cached

# Store a value in the cache
cached = Cached("my-cache-key")
cached.set("a JSON-serializable value", expiration=60)  # expires in 60 seconds

# Later, retrieve the value
cached = Cached("my-cache-key")
if cached.exists():
    print(cached.value)  # "a JSON-serializable value"
else:
    print("Cache miss or expired!")

Values are stored in a CachedItem database model, so you don't need to set up Redis or any external caching service.

Setting expiration

You can set expiration in several ways when calling set():

from datetime import datetime, timedelta
from plain.cache import Cached

cached = Cached("my-key")

# Seconds as int or float
cached.set("value", expiration=300)  # 5 minutes

# Timedelta
cached.set("value", expiration=timedelta(hours=1))

# Specific datetime
cached.set("value", expiration=datetime(2025, 12, 31, 23, 59, 59))

# No expiration (cached forever)
cached.set("value")

Checking and deleting

You can check if a cached item exists (and is not expired) using exists():

cached = Cached("my-key")

if cached.exists():
    # Cache hit - value is available
    data = cached.value
else:
    # Cache miss or expired - compute and store the value
    data = expensive_computation()
    cached.set(data, expiration=3600)

To delete a cached item:

cached = Cached("my-key")
deleted = cached.delete()  # Returns True if item existed, False otherwise

Querying cached items

The CachedItem model includes a custom queryset with filters for common queries:

from plain.cache.models import CachedItem

# Get all expired items
expired_items = CachedItem.query.expired()

# Get all unexpired items (with an expiration date in the future)
active_items = CachedItem.query.unexpired()

# Get items with no expiration (cached forever)
forever_items = CachedItem.query.forever()

Automatic cleanup

Expired cache items are not automatically deleted from the database. You can clean them up in two ways:

  1. Using chores: If you have plain.chores set up, the ClearExpired chore will automatically delete expired items when chores run.

  2. Using the CLI: Run plain cache clear-expired manually or in a scheduled task.

CLI commands

The plain cache command group provides utilities for managing cached items:

  • plain cache stats - Show cache statistics (total, expired, unexpired, forever counts)
  • plain cache clear-expired - Delete all expired cache items
  • plain cache clear-all - Delete all cache items (prompts for confirmation)

Admin integration

If you have plain.admin installed, plain.cache automatically registers an admin viewset. You can browse cached items, see their keys, values, and expiration dates in the admin interface under the "Cache" section.

FAQs

What types of values can I cache?

Any JSON-serializable value: strings, numbers, booleans, lists, dicts, and None. Complex objects need to be serialized before caching.

What happens when I access an expired item?

The exists() method returns False for expired items, and value returns None. The expired item remains in the database until explicitly cleaned up.

Is there any observability built in?

Yes. Cache operations (exists, get, set, delete) are instrumented with OpenTelemetry spans, so you can see cache hits and misses in your tracing backend.

Installation

Install the plain.cache package from PyPI:

uv add plain.cache

Add plain.cache to your INSTALLED_PACKAGES:

# app/settings.py
INSTALLED_PACKAGES = [
    # ...
    "plain.cache",
]

Run migrations to create the cache tables:

plain migrate

Try it out:

from plain.cache import Cached

cached = Cached("test-key")
cached.set({"hello": "world"}, expiration=300)
print(cached.value)  # {'hello': 'world'}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plain_cache-0.26.0.tar.gz (8.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plain_cache-0.26.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file plain_cache-0.26.0.tar.gz.

File metadata

  • Download URL: plain_cache-0.26.0.tar.gz
  • Upload date:
  • Size: 8.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for plain_cache-0.26.0.tar.gz
Algorithm Hash digest
SHA256 380a73ecd6625e602bf72950662fe1f40b429777b483f83c9743e6c9730872bd
MD5 12ff9438c87c1afcdf330d453bcfc8b1
BLAKE2b-256 b6040721f504018ecc71669edfb142edb4a2530f8956ede3ccfa8536fe5d6f34

See more details on using hashes here.

File details

Details for the file plain_cache-0.26.0-py3-none-any.whl.

File metadata

  • Download URL: plain_cache-0.26.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for plain_cache-0.26.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3de00418454d1728f609fbf1cdff5a5adb38549406e42fcadd5f9bf1276d4a8d
MD5 dde3c0534048129d440c97ecd0e9bfa5
BLAKE2b-256 2d2ced4bd0dbffee8884ce468eb19f7203cc032415698ad605745295bf8a4735

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page