Media Handling¶
Django Cast provides comprehensive media management for images, audio, video, and generic files. All media is user-owned and integrates seamlessly with Wagtail’s admin interface and Django’s storage backends.
Overview¶
Media handling features:
User ownership: All media is associated with the uploading user
Multiple formats: Support for various image, audio, and video formats
Automatic processing: Image renditions, audio duration, video posters
Storage flexibility: Works with local storage, S3, or any Django storage backend
Performance optimized: Rendition caching, metadata storage, bulk operations
API access: Full REST API for media operations
Media Types¶
Images¶
Django Cast extends Wagtail’s image handling with responsive image generation.
Features:
Automatic rendition generation for multiple screen sizes
Modern format support (AVIF, WebP, JPEG, PNG)
Responsive images with srcset and sizes attributes
User-based filtering in admin
Bulk rendition creation
Configuration:
# Image formats to generate (default)
CAST_IMAGE_FORMATS = ["jpeg", "avif"]
# Regular image slots
CAST_REGULAR_IMAGE_SLOT_DIMENSIONS = [
(1110, 740),
]
# Gallery image slots
CAST_GALLERY_IMAGE_SLOT_DIMENSIONS = [
(1110, 740), # Modal image
(120, 80), # Thumbnail
]
Each tuple defines a target slot in the layout. django-cast then generates the
responsive rendition widths needed for multiple pixel densities, so one slot
still produces multiple image files in srcset.
Audio¶
Comprehensive audio file management with podcast support.
Supported Formats:
MP3: Universal compatibility
M4A: Apple ecosystem
OGA: Ogg Vorbis
OPUS: Modern codec
Features:
Automatic duration detection (requires FFprobe)
Multiple format upload support
Chapter marks with timestamps
Transcript association
Podlove Web Player integration
Metadata caching for performance
Audio Metadata:
# Automatically extracted
audio.duration # Duration as timedelta
audio.data # JSON metadata including file sizes
Video¶
Video file support with automatic poster generation.
Features:
Automatic poster frame extraction (requires FFmpeg)
Configurable poster timestamp
Dimension detection
Format support: Any format browsers can play
MIME type detection
Poster Generation:
# Customize poster extraction time
video.poster_seconds = 5.0 # Extract at 5 seconds
video.create_poster() # Regenerate poster
Files¶
Generic file storage for other document types.
Features:
Simple file upload and storage
User association
Path tracking for cleanup
Storage Configuration¶
Django Cast supports flexible storage backends.
Local Storage¶
Default configuration using Django’s file storage:
# Media files served from
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
S3 Storage¶
Configure S3 for production:
# Using django-storages
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
# Disable Wagtail's automatic cleanup for S3
DELETE_WAGTAIL_IMAGES = False
Multiple Storage Backends¶
Configure separate storage backends through Django’s STORAGES setting:
STORAGES = {
"default": {
"BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
},
"production": {
"BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
},
"backup": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
"OPTIONS": {
"location": "/backup/media",
},
},
}
Image Renditions¶
Responsive Image Generation¶
Cast automatically generates responsive images:
<!-- Generated HTML -->
<picture>
<source type="image/avif"
srcset="image.avif.150w 150w,
image.avif.300w 300w,
image.avif.450w 450w"
sizes="(max-width: 480px) 100vw, 50vw">
<img src="image.jpg"
srcset="image.jpg.150w 150w,
image.jpg.300w 300w,
image.jpg.450w 450w"
sizes="(max-width: 480px) 100vw, 50vw"
alt="Description">
</picture>
Rendition Filters¶
Custom rendition generation:
# Generate specific rendition
rendition = image.get_rendition('fill-300x300')
# Bulk create renditions
gallery.create_renditions()
Performance Optimization¶
Renditions are cached after first generation
Bulk operations for multiple images
Repository pattern prefetches renditions
Minimal database queries
Audio Features¶
Chapter Marks¶
Add navigable chapters to audio:
from cast.models import ChapterMark
ChapterMark.objects.create(
audio=audio,
start="00:05:30",
title="Introduction",
link="https://example.com",
image="https://example.com/chapter.jpg"
)
Transcripts¶
Multiple transcript format support:
from cast.models import Transcript
transcript = Transcript.objects.create(
audio=audio,
podlove=podlove_file, # JSON format
vtt=vtt_file, # WebVTT format
dote=dote_file # DOTe JSON format
)
Player Integration¶
Audio data formatted for Podlove Web Player:
# Automatic player data generation
player_data = {
"audio": audio.audio, # Format list
"chapters": audio.chapters, # Chapter marks
"title": audio.title,
"subtitle": audio.subtitle,
}
Video Processing¶
Poster Generation¶
Automatic poster frame extraction:
# Generate poster at upload
video = Video.objects.create(
user=request.user,
title="My Video",
original=video_file
)
# Poster created automatically
# Regenerate with different timestamp
video.poster_seconds = 10.0
video.create_poster()
Dimension Detection¶
Video dimensions and orientation:
width, height = video._get_video_dimensions()
is_portrait = height > width
Management Commands¶
Media Maintenance¶
Find orphaned media files:
python manage.py media_stale
python manage.py media_stale --delete # Remove orphaned files
Backup and Restore¶
Sync media between storages:
# Backup from production to backup storage
python manage.py media_backup
# Restore from backup to production
python manage.py media_restore
Media Analysis¶
Analyze storage usage:
python manage.py media_sizes
Rendition Management¶
Create missing renditions:
python manage.py sync_renditions
Regenerate video posters:
python manage.py recalc_video_posters
User Ownership¶
Access Control¶
All media is filtered by user:
# In views
images = Image.objects.filter(user=request.user)
# In admin
# Automatically filtered by logged-in user
Search Integration¶
Media is searchable:
from wagtail.search.backends import get_search_backend
search_backend = get_search_backend()
results = search_backend.search("podcast", Audio)
API Integration¶
Upload via API¶
# POST /api/audios/
{
"title": "Episode 1",
"file": <multipart file>
}
Media in StreamField¶
Media blocks in post content:
body = StreamField([
("image", ImageChooserBlock()),
("gallery", GalleryBlock()),
("video", VideoChooserBlock()),
("audio", AudioChooserBlock()),
])
Best Practices¶
Maintenance¶
Run media_stale periodically to clean orphaned files
Backup media files regularly
Test restore procedures
Troubleshooting¶
Common Issues¶
FFmpeg/FFprobe not found:
Install FFmpeg for audio/video processing:
# Ubuntu/Debian
sudo apt-get install ffmpeg
# macOS
brew install ffmpeg
Large file uploads failing:
Adjust Django settings:
# Increase upload limits
DATA_UPLOAD_MAX_MEMORY_SIZE = 50 * 1024 * 1024 # 50MB
FILE_UPLOAD_MAX_MEMORY_SIZE = 50 * 1024 * 1024 # 50MB
Renditions not generating:
Check Pillow installation and image format support:
python -m PIL --version
S3 permissions errors:
Ensure bucket policy allows required operations:
GetObject
PutObject
DeleteObject (if DELETE_WAGTAIL_IMAGES is True)