Джанго каналы, чтобы изменить размер изображения
У меня есть модель для фото, с двумя полями изображения. Один для исходного изображения, а другой для измененной версии исходного изображения.
class Photo(models.Model):
user = models.ForeignKey(User)
image_original = models.ImageField(
upload_to=get_upload_file_name,
width_field="image_original_width",
height_field="image_original_height",
blank=True
)
image_original_width = models.IntegerField(default=0)
image_original_height = models.IntegerField(default=0)
image_470 = models.ImageField(
upload_to=get_upload_file_name,
width_field="image_470_width",
height_field="image_470_height",
blank=True
)
image_470_width = models.IntegerField(default=0)
image_470_height = models.IntegerField(default=0)
Причина, по которой я выбрал django-channles, заключалась в том, что я уже использовал его для целей веб-сокета, и в документах они сказали: "... Кроме того, существует множество некритических задач, которые приложения могут легко разгрузить до окончания ответ отправлен - как сохранение вещей в кэш или миниатюра вновь загруженных изображений. ",
Как я могу использовать django-каналы для изменения размера изображения, чтобы оно имело ширину 470 пикселей и автоматическую высоту, используя sorl-thumbnail или django-imagekit или любым другим способом?
1 ответ
Если вы хотите использовать sorl-thumbnail, вам не нужно ничего делать в коде вашей модели. Просто имейте такой класс:
class Photo(models.Model):
user = models.ForeignKey(User)
image = models.ImageField(
upload_to=get_upload_file_name,
width_field="width",
height_field="height",
blank=True
)
width = models.IntegerField(default=0)
height = models.IntegerField(default=0)
И всякий раз, когда вам нужно изображение размером 470 пикселей, сделайте так в своем шаблоне:
{% load thumbnail %}
...
{# Specifying width only here. #}
{# If you want a height constraint as well use e.g. "470x1000". #}
{% thumbnail photo.image "470" as im %}
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}
Вот и все - sorl-thumbnail позаботится обо всем остальном (масштабирование по первому запросу, обработка кэша и т. Д.). Он работает по требованию, то есть изменение размера будет выполнено при первом доступе (когда встречается тег шаблона) - что обычно нормально. Единственное, о чем вы должны помнить, это то, что sorl-thumbnail не будет работать хорошо, если у вас мало памяти. Если вы храните медиа на локальном диске - это нормально. Если ваш сервер хранения, скажем, Amazon S3 - не делайте этого.
Удобная часть этого заключается в том, что вам понадобятся другие размеры миниатюр, вы просто говорите sorl-thumnail, что они вам нужны, прямо в коде шаблона. Никаких изменений модели не требуется.
Если вы хотите убедиться, что миниатюры предварительно созданы с помощью sorl-thumbnail, вы можете вызвать get_thumbnail
явно или использовать, например, задачу Celery, которая будет выполняться get_thumbnail
(игнорируя результат) для вас, например
@app.task
def ensure_thumbnail(photo_pk, size="470"):
photo = Photo.objects.get(pk=photo_pk)
get_thumbnail(photo.image, size)
И всякий раз, когда вы видите новую загрузку, звоните ensure_thumbnail.delay(photo.pk)
,
Не забудьте проверить примеры для получения дополнительной информации.
Если вы чувствуете, что этот подход не тот, каким вы хотите, или у вас медленное хранилище, используйте django-imagekit. Я не очень знаком с ним (сам не использовал в производстве), но на основании документации это выглядит так:
Ваша модель будет выглядеть так:
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit
...
class Photo(models.Model):
user = models.ForeignKey(User)
image_original = models.ImageField(
upload_to=get_upload_file_name,
width_field="image_original_width",
height_field="image_original_height",
blank=True
)
image_original_width = models.IntegerField(default=0)
image_original_height = models.IntegerField(default=0)
# I haven't found a way to not specify the height.
image_470 = ImageSpecField(source="image_original",
processors=[ResizeToFit(470, 1000)],
format="JPEG")
(Как и sorl-thumbnail, это на самом деле не создаст поле базы данных. Если вам абсолютно необходим полностью управляемый независимый файл изображения с собственным полем базы данных - кажется, что ваш лучший вариант - явно генерировать миниатюры в Photo.save
используя голую библиотеку Pillow.)
Тогда это просто и понятно:
<img src="{{ photo.image_470.url }}"
width="{{ photo.image_470.width }}"
height="{{ photo.image_470.height }}"
alt="..." />
Обязательно ознакомьтесь с документацией по кешированию, которая объясняет, как работает кеширование (и для асинхронной генерации thumnails, вы захотите так).