Django - загрузка файла в папку с именем id объекта

Я пытался сделать это таким образом, но вместо {{product.id}} папка называется None. Я прочитал несколько статей об этом, и выяснил, что это потому, что папка создается до всего объекта. Так как же мне сделать, чтобы это работало?

models.py

def getImageURL(self, filename):
    return "products_images/" + str(self.pk) + "/product_image.png"
    

class Product(models.Model):
    name = models.CharField(max_length=200)
    image = models.ImageField(upload_to=getImageURL, default="media/static/products_images/default.png" )

редактирование: изменил свою функцию на

def getImageURL(instance, filename):
    return "products_images/{}/product_image.png".format(instance.id)

но это работает только при редактировании существующего объекта. Когда я пытаюсь создать новый, id устанавливается в None

Проблема заключается в следующем:

  • У экземпляра еще нет первичного ключа до его создания
  • Когда экземпляр будет сохранен в базе данных, тогда вы сможете получить первичный ключ

Может быть, как-то использовать сигналы? Сделать логику в представлении после его сохранения?

Альтернативный вариант для pk:

Вы можете сгенерировать UUID для объекта.

    id = models.UUIDField(
         primary_key = True,
         default = uuid.uuid4,
         editable = False)

Или альтернативно:

Посмотрите на этот пакет, вы можете установить алфавит uuid, длину и некоторые другие параметры. Это позволит вам получить доступ к id, наверняка (то же самое с uuid).

https://pypi.org/project/shortuuid/

id = ShortUUIDField(
        length=16,
        max_length=40,
        prefix="id_",
        alphabet="abcdefg1234",
        primary_key=True,
    )

Сиденот:

def getImageURL(self, filename): #Self would normally be defined as instance, but I suppose this is just semantics.

Это происходит потому, что id сохраняется в модели после вызова save(). Первой догадкой было бы использовать save(), чтобы получить объект в ответ. Но save() ничего не возвращает. Поэтому я собрал небольшой пример

class Thingy(models.Model):
    name = models.CharField(
        _('name'),
        max_length=64,
    )

    def save(self, *args, **kwargs):
        super(Thingy, self).save(*args, **kwargs)
        print(self.pk)

Мой тест был:

>>> t = Thingy(name="lol")
>>> t.save()
1

И он напечатал первичный ключ, так как save() мутирует self. Можно проверить, существует ли pk перед save(). Если да, просто добавьте путь к изображению. Если нет. Выполните сначала save(), манипулируйте путем изображения с помощью pk и снова сохраните объект. Это не слишком элегантно, но, полагаю, это единственный способ.

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