- 1. Реалізація
WEBP - це формат стиснення зображень, запропонований Google в 2010 році. Головною його перевагою є низький розмір без видимих втрат якості, порівняно з такими форматами, як JPEG або PNG. Тому логічно використовувати цей формат для зберігання зображень на сайті, особливо якщо у вас немає необхідності зберігати оригінали зображень на сайті.
Після тривалих пошуків я так і не знайшов готового та простого рішення, яке б підтримувало конвертацію зображень у формат WEBP на льоту.
Тому вирішив написати свій варіант, який у підсумку складається з пари десяток рядків та простий як дерев'яна дошка.
Реалізація
Вся реалізація складається із двох частин:
- WEBPFieldFile - клас спадкоємець від ImageFieldFile, який здійснює збереження файлу з автоматичною конвертацією в WEBP формат.
- WEBPField - клас спадковий від ImageField, який використовує WEBPFieldFile замість ImageFieldFile
І все це розміщується в одному файлі fields.py.
Для роботи із зображеннями знадобиться бібліотека Pillow. Тому встановимо її. Втім, навіть просто для використання полів ImageField вам буде потрібна ця бібліотека.
- pip install Pillow
fields.py
Створіть у своєму додатку файли fields.py і додайте до нього наступний код
- # -*- coding: utf-8 -*-
- import io
- from PIL import Image
- from django.core.files.base import ContentFile
- from django.db import models
- from django.db.models.fields.files import ImageFieldFile
- class WEBPFieldFile(ImageFieldFile):
- def save(self, name, content, save=True):
- content.file.seek(0)
- image = Image.open(content.file)
- image_bytes = io.BytesIO()
- image.save(fp=image_bytes, format="WEBP")
- image_content_file = ContentFile(content=image_bytes.getvalue())
- super().save(name, image_content_file, save)
- class WEBPField(models.ImageField):
- attr_class = WEBPFieldFile
Як бачите, в даному коді в класі WEBPFieldFile перевизначено метод save() який отримує як вхідний аргумент ім'я та вміст файлу для збереження, конвертує вміст файлу у формат WEBP і після чого методом базового класу зберігає файл на диск. А клас WEBPField такий самий як і ImageField з тією лише різницею, що використовує модифікований фаріант класу для обробки зображення.
models.py
А тепер давайте скористаємося новим полем зображення у нашій моделі для фотографії.
- # -*- coding: utf-8 -*-
- import os
- import uuid
- from django.conf import settings
- from django.db import models
- from django.utils.translation import gettext_lazy as _
- from photo.fields import WEBPField
- def image_folder(instance, filename):
- return 'photos/{}.webp'.format(uuid.uuid4().hex)
- class Photo(models.Model):
- user = models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
- height = models.IntegerField(verbose_name=_('Height'), default=0, blank=True, null=True)
- width = models.IntegerField(verbose_name=_('Width'), default=0, blank=True, null=True)
- image = WEBPField(
- verbose_name=_('Image'),
- upload_to=image_folder,
- height_field='height',
- width_field='width'
- )
Як бачите, використання даного поля WEBPField нічим не відрізняється від використання стандартного поля ImageField .
А як бонус в даному коді до функції image_folder я додав генерування випадкового унікального імені файлу за допомогою uuid .
Очень годно!