Automatic image thumbnail generation for Django storages (local & S3).
Project description
django-storage-thumbnails
Automatically generate image thumbnails whenever a file is saved through a Django storage backend. Works with local filesystem storage and Amazon S3 (via django-storages).
Install
pip install django-storage-thumbnails # local filesystem
pip install "django-storage-thumbnails[s3]" # + S3 support
Configure
Add the sizes you want to your Django settings. Sizes accept either a
(width, height) tuple or a "WxH" string:
THUMBNAIL_SIZES = {
"small": (10, 10),
"med": (20, 20),
}
Then point your model/field (or STORAGES) at a thumbnail-aware storage.
Local filesystem
from thumbnail_storage import ThumbnailFileSystemStorage
storage = ThumbnailFileSystemStorage()
name = storage.save("photos/cat.jpg", my_image_file)
# also writes: thumbnails/small/photos/cat.jpg, thumbnails/med/photos/cat.jpg
Amazon S3
from thumbnail_storage import ThumbnailS3Storage
storage = ThumbnailS3Storage(bucket_name="my-bucket")
storage.save("photos/cat.jpg", my_image_file)
In a model
from django.db import models
from thumbnail_storage import ThumbnailFileSystemStorage
class Photo(models.Model):
image = models.ImageField(
upload_to="photos/",
storage=ThumbnailFileSystemStorage(),
)
Getting thumbnail links
Thumbnails are stored under a dedicated thumbnails/<size>/ prefix so they can
never collide with or overwrite a user's uploaded file. Deleting the original
also removes its thumbnails.
storage.thumbnail_url("photos/cat.jpg", "small")
# -> "/media/thumbnails/small/photos/cat.jpg"
storage.get_thumbnails("photos/cat.jpg")
# -> {"small": "/media/thumbnails/small/photos/cat.jpg",
# "med": "/media/thumbnails/med/photos/cat.jpg"}
Use it with any backend
ThumbnailMixin can be mixed into any Django Storage subclass:
from thumbnail_storage import ThumbnailMixin
from storages.backends.azure_storage import AzureStorage
class ThumbnailAzureStorage(ThumbnailMixin, AzureStorage):
pass
Async generation with Celery (S3)
For S3, you usually don't want to block the upload request while thumbnails are generated. Use the async storage: it saves the original immediately and hands the thumbnail work to a Celery worker, which re-reads the original from S3 — so only the file name travels over the broker, never the image bytes.
pip install "django-storage-thumbnails[s3,celery]"
Register the storage under a key in STORAGES and pass that key as alias
(the worker uses it to rebuild the same backend):
# settings.py
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"thumbnails": {
"BACKEND": "thumbnail_storage.AsyncThumbnailS3Storage",
"OPTIONS": {"alias": "thumbnails", "bucket_name": "my-bucket"},
},
}
from django.core.files.storage import storages
storage = storages["thumbnails"]
storage.save("photos/cat.jpg", img) # returns immediately; thumbnails follow
Make sure your Celery app autodiscovers thumbnail_storage.tasks, and that the
worker can reach the same S3 bucket. If Celery isn't installed, generation
quietly falls back to running inline.
Fetching while a thumbnail is still being made
Names are deterministic, so thumbnail_url() returns the URL right away — even
before the worker finishes. Use it with a fallback to the original so there's no
broken image in the brief window before the thumbnail exists:
<img src="{{ small_url }}" onerror="this.onerror=null; this.src='{{ original_url }}'">
Need a guaranteed "ready" signal or to generate sizes only on first view? The
get_thumbnail_name and store_thumbnail methods are overridable — subclass to
record a status row or to generate lazily, without forking the package.
How it works
On _save, if the saved file's extension is a known image type and
THUMBNAIL_SIZES is non-empty, a thumbnail is generated for each size with
Pillow (Image.thumbnail, which preserves aspect ratio — so a "10x10" size is
a bounding box, not an exact crop) and saved under thumbnails/<key>/<name> in
the same backend. Non-images and unreadable files are passed through untouched,
and any per-size failure is logged and skipped without affecting the upload or
the other sizes. Override thumbnail_prefix to change the namespace, or
get_thumbnail_name / store_thumbnail to change naming or write behavior.
Cleanup on delete() removes the thumbnails for the current THUMBNAIL_SIZES
/ thumbnail_prefix. If you remove a size key or change the prefix later,
thumbnails generated under the old config are not tracked and won't be cleaned
up automatically — prune them out of band if needed.
Running the tests
pip install -e ".[test]"
pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_storage_thumbnails-0.1.1.tar.gz.
File metadata
- Download URL: django_storage_thumbnails-0.1.1.tar.gz
- Upload date:
- Size: 12.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d82d969fe363d32449f164413121d12006651e9f7c6d6c36923b1e228646605e
|
|
| MD5 |
b745fca106a6f5f9c164ddb53fed21b3
|
|
| BLAKE2b-256 |
483c8c8d55893a0c580c1f62c48085f95706b63c5cd8c3ef73766528757624ce
|
File details
Details for the file django_storage_thumbnails-0.1.1-py3-none-any.whl.
File metadata
- Download URL: django_storage_thumbnails-0.1.1-py3-none-any.whl
- Upload date:
- Size: 11.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dba1320782f794bf2fca46a99688353725f54cb683b3eef85e6825c0b52e2205
|
|
| MD5 |
921eb815244cbde43a94e77a22e60fe5
|
|
| BLAKE2b-256 |
c06fa7bc9fc9fad9bbe0dd83d38251b2aaa386312d7749b23f77721e672b599e
|