Вспомогательная функция Django для переименования загруженного пользователем изображения
В проекте django у меня есть модель с полем для изображений. Идея заключается в том, что пользователь загружает изображение, а django переименовывает его в соответствии с выбранным шаблоном перед сохранением в папке media.
Для этого я создал вспомогательный класс в отдельном файле utils.py. Класс будет вызываться в параметре upload_to
модели django ImageField. Изображения должны быть переименованы путем конкатенации свойств .name и .id созданного элемента. Проблема моего решения в том, что если изображение загружается при создании объекта элемента заново, то нет значения .id для использования (пока). Поэтому вместо, скажем, banana_12.jpg я получаю banana_None.jpg. Если вместо этого я загружаю изображение на уже существующий объект элемента, то изображение переименовывается правильно.
Вот мое решение. Как я могу улучшить код, чтобы он работал и на новом объекте?
Есть ли лучший способ сделать это?
# utils.py
from django.utils.deconstruct import deconstructible
import os
@deconstructible
class RenameImage(object):
"""Renames a given image according to pattern"""
def __call__(self, instance, filename):
"""Sets the name of an uploaded image"""
self.name, self.extension = os.path.splitext(filename)
self.folder = instance.__class__.__name__.lower()
image_name = f"{instance}_{instance.id}{self.extension}"
return os.path.join(self.folder, image_name)
rename_image = RenameImage()
# models.py
from .utils import rename_image
class Item(models.Model):
# my model for the Item object
name = models.CharField(max_length=30)
info = models.CharField(max_length=250, blank=True)
image = models.ImageField(upload_to=rename_image, blank=True, null=True) # <-- helper called here
# ...
Я создал вспомогательный класс RenameImage, который по причинам, описанным выше, работает правильно только в том случае, если объект уже существует.
Это невозможно, потому что id присваивается после сохранения. Вы должны использовать сигнал post_save и затем изменить имя файла. Для этого добавьте signal.py в app В файле apps.py переопределите функцию ready, чтобы добавить оператор import signals.py
apps.py
from django.apps import AppConfig
class AppNameConfig(AppConfig):
name = 'app_name'
def ready(self):
import app_name.signals
В init.py установите конфигурацию приложения по умолчанию
init.py
default_app_config = 'app_name.apps.AppNameConfig'
signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Item
@receiver(post_save, sender=Item)
def post_save(sender, instance: FilettoPasso, **kwargs):
if kwargs['created']:
print(instance.id)
instance.image.path = new path
instance.save()