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.2.tar.gz (8.8 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.2-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: plain_cache-0.26.2.tar.gz
  • Upload date:
  • Size: 8.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","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.2.tar.gz
Algorithm Hash digest
SHA256 c34d1a11ab8cd25a25b86142adae68661f6d639b9605e44ef76b18d908a5894d
MD5 3afcc43c4425d313c91779dc6f537a0c
BLAKE2b-256 30312f80999bff0b92bdec42376ae042082076292bb29b9a0629f74babc67092

See more details on using hashes here.

File details

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

File metadata

  • Download URL: plain_cache-0.26.2-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 58d730a441c7b3fbb68f50810ffea8a01ef56580c62d19c3fc850b64f5676527
MD5 d2ecbcb5f6433ce66fa9b67ae9faa760
BLAKE2b-256 abe1ce3e7d5b7268703d004254afa4235c11c865516222478c006445e1a29bdf

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