Как ограничить размеры картинок при загрузке в поле ImageField Django
Django хранит картинки в полях типа ImageField. В стандартном виде это поле не ограничивает размер загружаемого изображения. Поэтому разработчики применяют сторонние и самописные решения, чтобы не хранить на серверах гигабайты фото в высоком разрешении.
Установим минимальный размер картинки в поле ImageField
Определим метод clean модели и в нем проверим поле картинки ImageField. Сейчас проверим только минимальные размеры изображения. Вот как это сделать:
from django.core.exceptions import ValidationError
class Image(models.Model):
"""Модель картинки."""
image = models.ImageField('Картинка', upload_to='images')
def clean(self):
if self.image:
if self.image.width < 600 or self.image.height < 600:
raise ValidationError(
{'image': 'Минимальный размер картинки 600х600 пикселей. '}
)
return super().clean()
def save(self, force_insert, force_update, using, update_fields):
self.full_clean()
return super().save(force_insert, force_update, using, update_fields)
Метод save переопределяем, чтобы вызывать методы очистки при сохранении объектов модели вне админки. Если работаем с моделями только через административный раздел Django, метод save можно не переопределять.
Оформим код проверки размеров в виде функции, чтобы использовать его в других моделях с картинками без повторов.
def image_size_validator_factory(min_w=600, min_h=600, field_name='image'):
def validator(image):
if image.width < min_w or image.height < min_h:
raise ValidationError(
{field_name: f'Размер картинки от {min_w}х{min_h} пикселей. '}
)
return validator
Теперь перепишем метод clean модели с картинкой.
...
def clean(self):
if self.image:
image_size_validator_factory()(self.image)
return super().clean()
...
Ограничим максимальное разрешение картинки в модели Django
Большую картинку можно пережать в картинку поменьше. Сделаем это на стороне сервера, чтобы не раздражать пользователя лишними действиями при работе с сайтом.
Установим пакет django-resized. Эта батарейка Django позволяет контролировать загружаемые изображения: сжимать до нужных размеров, преобразовывать к нужному формату, нормализовать ориентацию и очищать метаданные.
Сначала в settings.py проекта пропишем настройки для django-resized:
DJANGORESIZED_DEFAULT_SIZE = [1920, 1920]
DJANGORESIZED_DEFAULT_SCALE = 1
DJANGORESIZED_DEFAULT_QUALITY = 86
DJANGORESIZED_DEFAULT_KEEP_META = True
DJANGORESIZED_DEFAULT_FORCE_FORMAT = 'JPEG'
DJANGORESIZED_DEFAULT_FORMAT_EXTENSIONS = {'JPEG': ".jpg"}
DJANGORESIZED_DEFAULT_NORMALIZE_ROTATION = True
Далее в модели изменим класс поля ImageField на ResizedImageField. В поле можно определить размер, до которого нужно сжимать загружаемые картинки. Сжатие работает по "большей стороне" и сохраняет соотношение сторон. Если не определить параметр size, то сработают дефолтные настройки из settings.py. Больше параметров ищите на странице документации django-resized.
from django_resized import ResizedImageField
class Image(models.Model):
"""Модель картинки."""
image = ResizedImageField('Картинка', upload_to='images', size=[1200, 1200])
...
Теперь загрузить получится только изображение от 600х600 пикселей, а большие фото админка автоматически сожмет до размера 1200х1200 пикселей. Также сайт преобразует картинки в JPEG формат.