Django База [2023]: Оптимизация изображений, загружаемых в Django, авто-чистка медиа 🌇 #42
Django предоставляет множество инструментов для обработки медиа-файлов, но часто возникают проблемы с удалением неиспользуемых файлов, которые могут занимать много места на сервере. В этой статье мы рассмотрим модуль django-cleanup, который может автоматически удалять неиспользуемые медиа-файлы, а оптимизацию изображений мы напишем через функционал Pillow.
Если вы хотите выразить благодарность автору сайта, статей и курса по Django, вы можете сделать это по ссылке ниже:
Установка и настройка django-cleanup
Для начала, нужно установить модуль django-cleanup, устанавливаем через терминал: pip install django-cleanup
Для использования django-cleanup нужно добавить его в список INSTALLED_APPS в файле settings.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sites',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sitemaps',
'modules.blog.apps.BlogConfig',
'modules.system.apps.SystemConfig',
'mptt',
'debug_toolbar',
'taggit',
'captcha',
'django_ckeditor_5',
'django_cleanup',
]
Теперь все неиспользуемые медиа-файлы будут автоматически удалены при вызове метода delete()
у объекта модели.
Ресайзинг и оптимизация изображения в Django
В нашем модуле services, в файле utils.py, который мы создавали ранее в этом уроке, создадим функционал для оптимизации изображения (перед этим у нас должна быть установлена библиотека Pillow):
from PIL import Image, ImageOps
def image_compress(image_path, height, width):
"""
Оптимизация изображений
"""
img = Image.open(image_path)
if img.mode != 'RGB':
img = img.convert('RGB')
if img.height > height or img.width > width:
output_size = (height, width)
img.thumbnail(output_size)
img = ImageOps.exif_transpose(img)
img.save(image_path, format='JPEG', quality=90, optimize=True)
Данный код представляет собой функцию image_compress()
, которая принимает путь к изображению, высоту и ширину, а затем оптимизирует изображение, если его размер превышает указанные значения.
Image.open(image_path)
- открывает изображение, указанное в переменной image_path при помощи библиотеки PIL (Python Imaging Library).if img.mode != 'RGB': img = img.convert('RGB')
- проверяет, что изображение имеет формат RGB. Если это не так, то изображение преобразуется в RGB.if img.height > height or img.width > width:
- проверяет, превышает ли высота или ширина изображения указанные значения. Если да, то изображение будет пропорционально уменьшено до размеров height и width с сохранением соотношения сторон.output_size = (height, width) img.thumbnail(output_size)
- уменьшает размер изображения, если оно превышает указанные размеры, сохраняя при этом соотношение сторон.img = ImageOps.exif_transpose(img)
- определяет ориентацию изображения и преобразует его в соответствии с EXIF-данными, чтобы изображение отображалось правильно.img.save(image_path, format='JPEG', quality=90, optimize=True)
- сохраняет оптимизированное изображение в указанном пути image_path в формате JPEG с качеством 90 и включенной оптимизацией.
Далее добавим функционал в модель Article, в нашем приложении blog, в файле models.py:
from django.db import models
from modules.services.utils import unique_slugify, image_compress
class Article(models.Model):
"""
Модель постов для сайта
"""
title = models.CharField(verbose_name='Заголовок', max_length=255)
slug = models.SlugField(verbose_name='Альт.название', max_length=255, blank=True, unique=True)
# Другие поля...
# Другие методы...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__thumbnail = self.thumbnail if self.pk else None
def save(self, *args, **kwargs):
"""
Сохранение полей модели при их отсутствии заполнения
"""
if not self.slug:
self.slug = unique_slugify(self, self.title)
super().save(*args, **kwargs)
if self.__thumbnail != self.thumbnail and self.thumbnail:
image_compress(self.thumbnail.path, width=500, height=500)
Таким образом мы добавили оптимизацию для изображение, которое сохраняется впервые, или изменяется, чтобы предотвратить повторную оптимизацию.
Также мы оптимизируем изображение с помощью функции image_comporess()
, в которую передаем путь изображения, длину и высоту в пикселях.