Джанго каналы, чтобы изменить размер изображения

У меня есть модель для фото, с двумя полями изображения. Один для исходного изображения, а другой для измененной версии исходного изображения.

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, вы захотите так).

Другие вопросы по тегам