Storage

django-snapshots uses two stacked protocols for storage. Third-party backends use structural subtyping — no inheritance from the protocol class is required.

Protocols

class django_snapshots.SnapshotStorage(*args, **kwargs)[source]

Minimum storage interface.

read and write use IO[bytes] file-like objects to avoid loading entire artifacts into memory.

list(prefix) returns all stored paths whose full path string starts with prefix. Pass "" to list everything.

__init__(*args, **kwargs)
delete(path: str) None[source]
exists(path: str) bool[source]
list(prefix: str) list[str][source]
read(path: str) IO[bytes][source]
write(path: str, content: IO[bytes]) None[source]
class django_snapshots.AdvancedSnapshotStorage(*args, **kwargs)[source]

Extended storage interface with streaming and atomic operations.

Required for snapshot_format="archive" and for future incremental backup support.

atomic_move(src: str, dst: str) None[source]
recursive_list(prefix: str) list[str][source]
stream_read(path: str) Iterator[bytes][source]
stream_write(path: str, chunks: Iterator[bytes]) None[source]
sync(src_prefix: str, dst_prefix: str) None[source]

Guard function

django_snapshots.storage.protocols.requires_advanced_storage(backend: SnapshotStorage, operation: str) None[source]

Raise SnapshotStorageCapabilityError if backend is not an AdvancedSnapshotStorage.

Call this at the start of any function that requires the extended interface.

Built-in backends

LocalFileSystemBackend

The default backend. Implements the full AdvancedSnapshotStorage interface. All paths are relative to the configured location directory, which is created automatically if it does not exist.

Use this backend for local development and single-server deployments.

from django_snapshots.storage import LocalFileSystemBackend

storage = LocalFileSystemBackend(location="/var/backups/snapshots")
class django_snapshots.LocalFileSystemBackend(location: str)[source]

Store snapshots as files in a local directory.

Satisfies AdvancedSnapshotStorage — the default backend is never subject to OOM on large artifacts.

Args:
location: Absolute path to the root directory for snapshot storage.

Created automatically if it does not exist.

__init__(location: str) None[source]
atomic_move(src: str, dst: str) None[source]
delete(path: str) None[source]
exists(path: str) bool[source]
list(prefix: str) list[str][source]
read(path: str) IO[bytes][source]
recursive_list(prefix: str) list[str][source]
stream_read(path: str) Iterator[bytes][source]
stream_write(path: str, chunks: Iterator[bytes]) None[source]
sync(src_prefix: str, dst_prefix: str) None[source]

Copy all files under src_prefix to dst_prefix.

If dst_prefix is an absolute path string, copies files there instead (used for cross-backend sync in tests).

write(path: str, content: IO[bytes]) None[source]

DjangoStorageBackend

Wraps any django.core.files.storage.Storage instance to satisfy the SnapshotStorage basic protocol. Does not satisfy AdvancedSnapshotStorage.

Use this backend when you already have a configured Django storage (e.g. django-storages S3 backend) and only need basic upload/download.

from django.core.files.storage import FileSystemStorage
from django_snapshots.storage import DjangoStorageBackend

storage = DjangoStorageBackend(storage=FileSystemStorage(location="/tmp/snaps"))
class django_snapshots.DjangoStorageBackend(storage: Storage)[source]

Wrap any Django Storage backend as a SnapshotStorage.

Satisfies SnapshotStorage via structural subtyping. Does not satisfy AdvancedSnapshotStorage — use LocalFileSystemBackend when streaming or atomic operations are required.

Args:

storage: Any django.core.files.storage.Storage instance.

__init__(storage: Storage) None[source]
delete(path: str) None[source]
exists(path: str) bool[source]
list(prefix: str) list[str][source]
read(path: str) IO[bytes][source]
write(path: str, content: IO[bytes]) None[source]

Writing a custom backend

Implement all methods of SnapshotStorage (or AdvancedSnapshotStorage) on any class. No base class is needed — Python’s structural subtyping will recognise it automatically:

from typing import IO, Iterator

class MyS3Backend:
    def read(self, path: str) -> IO[bytes]: ...
    def write(self, path: str, content: IO[bytes]) -> None: ...
    def list(self, prefix: str) -> list[str]: ...
    def delete(self, path: str) -> None: ...
    def exists(self, path: str) -> bool: ...
    # Add the five AdvancedSnapshotStorage methods to satisfy that tier too.