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.3.tar.gz (8.9 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.3-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: plain_cache-0.26.3.tar.gz
  • Upload date:
  • Size: 8.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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.3.tar.gz
Algorithm Hash digest
SHA256 71751b9e2feeafe2bb46c605d72cb2c615b2e364f6fa0b1bc1e67a2901d39cd6
MD5 2e445c43bf99ae33e4411c7e678921d6
BLAKE2b-256 04ce899eeb9e22797039c60f720f725369adbdce1bc6e4e007dec10e2bdb7ef9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: plain_cache-0.26.3-py3-none-any.whl
  • Upload date:
  • Size: 14.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 2894765119388dbd2db799c2a3b7d3d8b4f7b00a3b6f217a89d6ff1636cdb3a3
MD5 6b909053b1b019615bf32ba16d1eb79e
BLAKE2b-256 26d05f260f779a69b168e0be89c1914a20bd7f6fe99987aaf8e2e25beecaadab

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