Вспомогательная функция 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()


    
Вернуться на верх