Отложите сохранение поля Django ImageField до тех пор, пока объект не получит pk
У меня есть модель Django для книги, которая имеет поле slug
, которое является хэшем, основанным на ее pk
. У него также есть thumbnail
, который сохраняется по пути, включающему этот slug
.
В Admin, если я создаю и сохраняю книгу без эскиза, а затем добавляю эскиз и снова сохраняю книгу, это работает: эскиз сохраняется в /media/books/<slug>/foo.jpg
.
НО если я создаю книгу с уменьшенным изображением и сохраняю ее, уменьшенное изображение сохраняется до того, как может быть сгенерировано slug
, поэтому оно сохраняется в /media/books/foo.jpg
. Это происходит потому, что файлы сохраняются до модели.
Я хотел бы всегда включать slug
в путь миниатюры, но не могу понять, как отложить сохранение миниатюры до тех пор, пока не будет сгенерирована slug
. Есть идеи?
from django.db import models
from hashes import Hashids
def upload_path(instance, filename):
return "/".join([books, instance.slug, filename])
class Book(models.Model):
title = models.CharField(null=False, blank=False, max_length=255)
slug = models.SlugField(max_length=10, null=False, blank=True)
thumbnail = models.ImageField(
upload_to=upload_path, null=False, blank=True, default=""
)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not self.slug:
# Now we have a pk, generate a slug if it doesn't have one.
hashids = Hashids(salt="my salt", min_length=5)
self.slug = hashids.encode(self.pk)
kwargs["force_insert"] = False
self.save(*args, **kwargs)
(Я знаю, что хэширование небезопасно; кто-то может узнать pk
из slug
. Я не против этого для данного случая использования.)
Я думаю, что ответ заключается в перемещении файла в нужное место после генерации пк. модель:
import os
from django.conf import settings
from django.db import models
from hashes import Hashids
def upload_path(instance, filename):
return "/".join([books, instance.slug, filename])
class Book(models.Model):
# field definitions here
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not self.slug:
# Now we have a pk, generate a slug if it doesn't have one.
hashids = Hashids(salt="my salt", min_length=5)
self.slug = hashids.encode(self.pk)
if self.thumbnail and f"/{self.slug}/" not in self.thumbnail.path:
# Move the thumbnail to correct location.
initial_path = self.thumbnail.path
filename = os.path.basename(initial_path)
new_name = upload_path(self, filename)
new_path = os.path.join(settings.MEDIA_ROOT, new_name)
if not os.path.exists(os.path.dirname(new_path)):
# Make the slug directory if it doesn't exist.
os.makedirs(os.path.dirname(new_path))
os.rename(initial_path, new_path)
self.thumbnail.name = new_name
kwargs["force_insert"] = False
super().save(*args, **kwargs)