or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-interface.mdapi.mdcontent-fields.mdcontrib.mdindex.mdmedia.mdpage-models.mdsearch.mdsystem-integration.mdtemplates.mdworkflows.md

media.mddocs/

0

# Media Management

1

2

Comprehensive media management with image processing, renditions, document handling, and collection-based organization. Wagtail provides powerful tools for managing images, documents, and other media assets with automated processing and optimization.

3

4

## Capabilities

5

6

### Image Management

7

8

Core image model and processing capabilities for handling images with automatic optimization and multiple renditions.

9

10

```python { .api }

11

class Image(AbstractImage):

12

"""

13

Core image model with processing and metadata capabilities.

14

15

Properties:

16

title (str): Image title/alt text

17

file (ImageField): The actual image file

18

width (int): Original image width in pixels

19

height (int): Original image height in pixels

20

created_at (datetime): When image was uploaded

21

uploaded_by_user (User): User who uploaded the image

22

focal_point_x (int): X coordinate of focal point

23

focal_point_y (int): Y coordinate of focal point

24

focal_point_width (int): Width of focal point area

25

focal_point_height (int): Height of focal point area

26

file_size (int): File size in bytes

27

file_hash (str): SHA1 hash of file content

28

collection (Collection): Collection this image belongs to

29

"""

30

title: str

31

file: ImageField

32

width: int

33

height: int

34

created_at: datetime

35

uploaded_by_user: User

36

focal_point_x: int

37

focal_point_y: int

38

focal_point_width: int

39

focal_point_height: int

40

file_size: int

41

file_hash: str

42

collection: Collection

43

44

def get_rendition(self, filter):

45

"""

46

Get or create a rendition of this image with specified operations.

47

48

Parameters:

49

filter (str or Filter): Image operations to apply

50

51

Returns:

52

Rendition: Processed image rendition

53

"""

54

55

def get_upload_to(self, filename):

56

"""Get the upload path for this image file."""

57

58

def get_usage(self):

59

"""Get all places where this image is used."""

60

61

def is_portrait(self):

62

"""Check if image is in portrait orientation."""

63

64

def is_landscape(self):

65

"""Check if image is in landscape orientation."""

66

67

class AbstractImage(models.Model):

68

"""

69

Base class for custom image models.

70

71

Inherit from this to create custom image models with additional fields.

72

"""

73

def save(self, *args, **kwargs):

74

"""Save image with automatic metadata extraction."""

75

76

def get_willow_image(self):

77

"""Get Willow image object for processing."""

78

79

class Rendition(AbstractRendition):

80

"""

81

Processed version of an image with specific operations applied.

82

83

Properties:

84

image (Image): Source image this rendition was created from

85

filter_spec (str): Operations applied to create this rendition

86

file (ImageField): The processed image file

87

width (int): Rendition width in pixels

88

height (int): Rendition height in pixels

89

focal_point_key (str): Focal point used for this rendition

90

"""

91

image: Image

92

filter_spec: str

93

file: ImageField

94

width: int

95

height: int

96

focal_point_key: str

97

98

def img_tag(self, extra_attrs=None):

99

"""Generate HTML img tag for this rendition."""

100

101

def attrs(self, extra_attrs=None):

102

"""Get HTML attributes dict for this rendition."""

103

104

class AbstractRendition(models.Model):

105

"""

106

Base class for custom rendition models.

107

"""

108

def save(self, *args, **kwargs):

109

"""Save rendition with automatic file generation."""

110

```

111

112

### Image Operations

113

114

Image processing operations for creating renditions with different sizes and effects.

115

116

```python { .api }

117

class Filter:

118

"""

119

Represents a set of image operations to apply.

120

121

Parameters:

122

spec (str): Filter specification string (e.g., 'fill-300x200|jpegquality-80')

123

"""

124

def __init__(self, spec):

125

"""Initialize filter with operation specification."""

126

127

def run(self, willow_image, image):

128

"""Apply filter operations to image."""

129

130

# Image operation classes

131

class Fill:

132

"""

133

Fill operation that crops and resizes to exact dimensions.

134

135

Parameters:

136

width (int): Target width in pixels

137

height (int): Target height in pixels

138

"""

139

def __init__(self, width, height):

140

"""Initialize fill operation."""

141

142

class FillMax:

143

"""

144

Fill operation with maximum dimensions constraint.

145

146

Parameters:

147

width (int): Maximum width in pixels

148

height (int): Maximum height in pixels

149

"""

150

def __init__(self, width, height):

151

"""Initialize fill max operation."""

152

153

class Width:

154

"""

155

Resize operation that sets width and maintains aspect ratio.

156

157

Parameters:

158

width (int): Target width in pixels

159

"""

160

def __init__(self, width):

161

"""Initialize width resize operation."""

162

163

class Height:

164

"""

165

Resize operation that sets height and maintains aspect ratio.

166

167

Parameters:

168

height (int): Target height in pixels

169

"""

170

def __init__(self, height):

171

"""Initialize height resize operation."""

172

173

class Min:

174

"""

175

Resize operation based on minimum dimension.

176

177

Parameters:

178

dimension (int): Minimum dimension in pixels

179

"""

180

def __init__(self, dimension):

181

"""Initialize min resize operation."""

182

183

class Max:

184

"""

185

Resize operation based on maximum dimension.

186

187

Parameters:

188

dimension (int): Maximum dimension in pixels

189

"""

190

def __init__(self, dimension):

191

"""Initialize max resize operation."""

192

193

class Scale:

194

"""

195

Scale operation that resizes by percentage.

196

197

Parameters:

198

percent (int): Scale percentage (100 = original size)

199

"""

200

def __init__(self, percent):

201

"""Initialize scale operation."""

202

203

class CropToPoint:

204

"""

205

Crop operation that centers on a specific point.

206

207

Parameters:

208

width (int): Crop width in pixels

209

height (int): Crop height in pixels

210

x (int): X coordinate of center point

211

y (int): Y coordinate of center point

212

"""

213

def __init__(self, width, height, x, y):

214

"""Initialize crop to point operation."""

215

```

216

217

### Document Management

218

219

Document handling for files like PDFs, Word documents, spreadsheets, and other non-image media.

220

221

```python { .api }

222

class Document(AbstractDocument):

223

"""

224

Core document model for file management.

225

226

Properties:

227

title (str): Document title

228

file (FileField): The actual document file

229

created_at (datetime): When document was uploaded

230

uploaded_by_user (User): User who uploaded the document

231

collection (Collection): Collection this document belongs to

232

file_size (int): File size in bytes

233

file_hash (str): SHA1 hash of file content

234

"""

235

title: str

236

file: FileField

237

created_at: datetime

238

uploaded_by_user: User

239

collection: Collection

240

file_size: int

241

file_hash: str

242

243

def get_usage(self):

244

"""Get all places where this document is used."""

245

246

def get_file_size(self):

247

"""Get human-readable file size."""

248

249

def get_file_extension(self):

250

"""Get file extension."""

251

252

@property

253

def url(self):

254

"""Get URL for downloading this document."""

255

256

class AbstractDocument(models.Model):

257

"""

258

Base class for custom document models.

259

260

Inherit from this to create custom document models with additional fields.

261

"""

262

def save(self, *args, **kwargs):

263

"""Save document with automatic metadata extraction."""

264

265

def get_upload_to(self, filename):

266

"""Get the upload path for this document file."""

267

```

268

269

### Collection Management

270

271

Hierarchical organization system for media assets with permission control.

272

273

```python { .api }

274

class Collection(MP_Node):

275

"""

276

Hierarchical collection for organizing media assets.

277

278

Properties:

279

name (str): Collection name

280

path (str): Full path in collection hierarchy

281

"""

282

name: str

283

path: str

284

285

def get_descendants(self, inclusive=False):

286

"""

287

Get all descendant collections.

288

289

Parameters:

290

inclusive (bool): Whether to include self in results

291

292

Returns:

293

QuerySet: Descendant collections

294

"""

295

296

def get_ancestors(self, inclusive=False):

297

"""

298

Get all ancestor collections.

299

300

Parameters:

301

inclusive (bool): Whether to include self in results

302

303

Returns:

304

QuerySet: Ancestor collections

305

"""

306

307

def get_view_restrictions(self):

308

"""Get view restrictions applied to this collection."""

309

310

def get_edit_restrictions(self):

311

"""Get edit restrictions applied to this collection."""

312

313

@classmethod

314

def get_first_root_node(cls):

315

"""Get the root collection."""

316

317

class CollectionViewRestriction:

318

"""

319

Restricts collection viewing to specific users or groups.

320

321

Properties:

322

collection (Collection): Collection to restrict

323

restriction_type (str): Type of restriction ('password', 'groups', 'login')

324

password (str): Password for access (if password restriction)

325

groups (QuerySet): Groups with access (if groups restriction)

326

"""

327

collection: Collection

328

restriction_type: str

329

password: str

330

groups: QuerySet

331

```

332

333

### Media Utilities

334

335

Utility functions and classes for media processing and management.

336

337

```python { .api }

338

def get_image_model():

339

"""

340

Get the configured Image model class.

341

342

Returns:

343

Model: The Image model class being used

344

"""

345

346

def get_document_model():

347

"""

348

Get the configured Document model class.

349

350

Returns:

351

Model: The Document model class being used

352

"""

353

354

class SourceImageIOError(Exception):

355

"""Exception raised when source image cannot be processed."""

356

357

class InvalidFilterSpecError(Exception):

358

"""Exception raised when filter specification is invalid."""

359

360

def generate_signature(image_id, filter_spec, key=None):

361

"""

362

Generate security signature for image renditions.

363

364

Parameters:

365

image_id (int): ID of source image

366

filter_spec (str): Filter specification

367

key (bytes): Secret key for signing

368

369

Returns:

370

str: Security signature

371

"""

372

373

def verify_signature(signature, image_id, filter_spec, key=None):

374

"""

375

Verify security signature for image renditions.

376

377

Parameters:

378

signature (str): Signature to verify

379

image_id (int): ID of source image

380

filter_spec (str): Filter specification

381

key (bytes): Secret key for verification

382

383

Returns:

384

bool: Whether signature is valid

385

"""

386

```

387

388

## Usage Examples

389

390

### Working with Images

391

392

```python

393

from wagtail.images.models import Image

394

from wagtail.images import get_image_model

395

396

# Get image model (useful for custom image models)

397

ImageModel = get_image_model()

398

399

# Create/upload image

400

with open('photo.jpg', 'rb') as f:

401

image = Image(

402

title="My Photo",

403

file=File(f, name='photo.jpg')

404

)

405

image.save()

406

407

# Get different sized versions

408

thumbnail = image.get_rendition('fill-150x150|jpegquality-60')

409

medium = image.get_rendition('width-500')

410

large = image.get_rendition('fill-1200x800')

411

412

# Use in templates

413

print(f'<img src="{thumbnail.url}" alt="{image.title}">')

414

415

# Complex operations

416

hero_image = image.get_rendition('fill-1920x1080|format-webp|jpegquality-85')

417

responsive_thumb = image.get_rendition('max-400x400|format-webp')

418

419

# Focal point cropping

420

centered_crop = image.get_rendition('fill-300x200') # Uses focal point if set

421

```

422

423

### Image Operations and Filters

424

425

```python

426

from wagtail.images.models import Image

427

428

# Load an image

429

image = Image.objects.get(title="Hero Image")

430

431

# Basic operations

432

thumbnail = image.get_rendition('fill-200x200') # Crop to exact size

433

scaled = image.get_rendition('width-800') # Resize maintaining ratio

434

square = image.get_rendition('min-300') # Minimum dimension

435

compressed = image.get_rendition('original|jpegquality-70') # Compress

436

437

# Advanced operations

438

hero = image.get_rendition('fill-1920x1080|format-webp|jpegquality-90')

439

mobile = image.get_rendition('fill-800x600|format-webp|jpegquality-75')

440

441

# Multiple operations in sequence

442

processed = image.get_rendition('width-1000|height-600|jpegquality-80')

443

444

# Format conversion

445

webp_version = image.get_rendition('original|format-webp')

446

png_version = image.get_rendition('original|format-png')

447

448

# Responsive images with multiple renditions

449

renditions = {

450

'mobile': image.get_rendition('fill-400x300'),

451

'tablet': image.get_rendition('fill-800x600'),

452

'desktop': image.get_rendition('fill-1200x900'),

453

}

454

```

455

456

### Document Management

457

458

```python

459

from wagtail.documents.models import Document

460

from django.core.files import File

461

462

# Upload document

463

with open('report.pdf', 'rb') as f:

464

document = Document(

465

title="Annual Report 2023",

466

file=File(f, name='annual-report-2023.pdf')

467

)

468

document.save()

469

470

# Access document properties

471

print(f"File size: {document.get_file_size()}")

472

print(f"Extension: {document.get_file_extension()}")

473

print(f"Download URL: {document.url}")

474

475

# Find document usage

476

usage = document.get_usage()

477

for page in usage:

478

print(f"Used on: {page.title}")

479

480

# Organize in collections

481

from wagtail.models import Collection

482

483

reports_collection = Collection.objects.get(name="Reports")

484

document.collection = reports_collection

485

document.save()

486

```

487

488

### Collection Organization

489

490

```python

491

from wagtail.models import Collection

492

493

# Create collection hierarchy

494

root = Collection.get_first_root_node()

495

496

# Add main collections

497

marketing = root.add_child(name="Marketing")

498

products = root.add_child(name="Products")

499

500

# Add subcollections

501

brochures = marketing.add_child(name="Brochures")

502

social_media = marketing.add_child(name="Social Media")

503

504

product_photos = products.add_child(name="Product Photos")

505

documentation = products.add_child(name="Documentation")

506

507

# Organize media by collection

508

from wagtail.images.models import Image

509

510

# Move images to appropriate collections

511

hero_images = Image.objects.filter(title__icontains="hero")

512

for image in hero_images:

513

image.collection = marketing

514

image.save()

515

516

# Filter media by collection

517

marketing_images = Image.objects.filter(collection=marketing)

518

product_docs = Document.objects.filter(collection__path__startswith=products.path)

519

520

# Collection permissions

521

from wagtail.models import CollectionViewRestriction, Group

522

523

# Restrict collection to specific groups

524

marketing_group = Group.objects.get(name="Marketing Team")

525

restriction = CollectionViewRestriction.objects.create(

526

collection=marketing,

527

restriction_type='groups'

528

)

529

restriction.groups.add(marketing_group)

530

```

531

532

### Custom Image Model

533

534

```python

535

from wagtail.images.models import AbstractImage, AbstractRendition

536

from django.db import models

537

538

class CustomImage(AbstractImage):

539

"""Custom image model with additional metadata."""

540

photographer = models.CharField(max_length=255, blank=True)

541

caption = models.TextField(blank=True)

542

copyright_info = models.CharField(max_length=255, blank=True)

543

keywords = models.CharField(max_length=500, blank=True)

544

545

admin_form_fields = (

546

'title',

547

'file',

548

'collection',

549

'tags',

550

'photographer',

551

'caption',

552

'copyright_info',

553

'keywords',

554

'focal_point_x',

555

'focal_point_y',

556

'focal_point_width',

557

'focal_point_height',

558

)

559

560

class CustomRendition(AbstractRendition):

561

"""Custom rendition model for custom images."""

562

image = models.ForeignKey(

563

CustomImage,

564

on_delete=models.CASCADE,

565

related_name='renditions'

566

)

567

568

class Meta:

569

unique_together = (

570

('image', 'filter_spec', 'focal_point_key'),

571

)

572

573

# Configure custom models in settings.py

574

# WAGTAILIMAGES_IMAGE_MODEL = 'myapp.CustomImage'

575

```

576

577

### Template Usage with Images

578

579

```python

580

# In templates, use the image templatetag

581

{% load wagtailimages_tags %}

582

583

<!-- Basic image -->

584

{% image page.hero_image fill-800x400 as hero %}

585

<img src="{{ hero.url }}" alt="{{ hero.alt }}" width="{{ hero.width }}" height="{{ hero.height }}">

586

587

<!-- Responsive images -->

588

{% image page.hero_image fill-400x300 as mobile %}

589

{% image page.hero_image fill-800x600 as tablet %}

590

{% image page.hero_image fill-1200x900 as desktop %}

591

592

<picture>

593

<source media="(min-width: 1024px)" srcset="{{ desktop.url }}">

594

<source media="(min-width: 768px)" srcset="{{ tablet.url }}">

595

<img src="{{ mobile.url }}" alt="{{ page.hero_image.title }}">

596

</picture>

597

598

<!-- Multiple formats -->

599

{% image page.hero_image fill-800x600|format-webp as webp_version %}

600

{% image page.hero_image fill-800x600|format-jpeg as jpeg_version %}

601

602

<picture>

603

<source srcset="{{ webp_version.url }}" type="image/webp">

604

<img src="{{ jpeg_version.url }}" alt="{{ page.hero_image.title }}">

605

</picture>

606

```

607

608

### Programmatic Media Management

609

610

```python

611

from wagtail.images.models import Image

612

from wagtail.documents.models import Document

613

from django.core.files.storage import default_storage

614

615

# Bulk image processing

616

def generate_thumbnails():

617

"""Generate thumbnail renditions for all images."""

618

for image in Image.objects.all():

619

try:

620

# Pre-generate common sizes

621

image.get_rendition('fill-150x150')

622

image.get_rendition('fill-300x200')

623

image.get_rendition('width-800')

624

print(f"Generated thumbnails for: {image.title}")

625

except Exception as e:

626

print(f"Error processing {image.title}: {e}")

627

628

# Clean up unused renditions

629

def cleanup_renditions():

630

"""Remove unused image renditions to free storage."""

631

from wagtail.images.models import Rendition

632

633

# Delete renditions older than 30 days that haven't been accessed

634

old_renditions = Rendition.objects.filter(

635

created_at__lt=timezone.now() - timedelta(days=30)

636

)

637

638

for rendition in old_renditions:

639

if default_storage.exists(rendition.file.name):

640

default_storage.delete(rendition.file.name)

641

rendition.delete()

642

643

# Media analytics

644

def get_media_stats():

645

"""Get statistics about media usage."""

646

total_images = Image.objects.count()

647

total_documents = Document.objects.count()

648

649

# Calculate storage usage

650

image_storage = sum(img.file_size for img in Image.objects.all() if img.file_size)

651

doc_storage = sum(doc.file_size for doc in Document.objects.all() if doc.file_size)

652

653

return {

654

'total_images': total_images,

655

'total_documents': total_documents,

656

'image_storage_mb': image_storage / (1024 * 1024),

657

'document_storage_mb': doc_storage / (1024 * 1024),

658

}

659

```