django - 延迟保存 Django ImageField 直到对象有 pk
问题描述
我有一个 Book 的 Django 模型,它有一个slug
基于其pk
. 它还有一个thumbnail
which 被保存到包含 that 的路径中slug
。
在管理员中,如果我创建并保存没有缩略图的图书,然后添加缩略图并再次保存图书,则此方法有效:缩略图保存到/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)
(我知道 Hashids 不安全;有人可以pk
从slug
.
解决方案
我认为答案是在生成 pk 后将文件移动到正确的位置。该模型:
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)
推荐阅读
- bitbake - 如何覆盖引用包含的 bitbake conf
- kotlin - NoSuchElementException java.lang.Scanner
- firebase - Firebase 存储使用 490MB,但我没有存储桶?
- node.js - Docker 构建卡在网络运行中:'RUN npx webpack' - 不会移动到 dockerfile 中的下一步
- c++ - 只有负数才能正确添加
- php - 从一对多关系中删除记录
- php - Laravel 在 View 的另一个 @ 函数中使用 @ 函数
- git - 撤消远程仓库上的分阶段删除
- time - Gnuplot - 从分钟增加到天
- gitlab - Gitlab 在合并请求时运行管道作业