如何延迟保存Django ImageField直到模型对象生成主键pk后
你遇到的问题本质是Django处理ImageField文件存储的时机早于模型实例第一次保存生成slug的时机,所以upload_path函数在实例首次创建时拿不到slug值,导致路径错误。
修改方案
- 先修正
upload_path函数中的错误:原代码中的books是路径常量,需要加引号定义为字符串。 - 调整模型
save方法逻辑:首次保存前暂存上传的图片,先保存实例得到主键生成slug后,再回填图片执行第二次保存,此时文件存储就能拿到正确的slug值。
完整修改后代码
from django.db import models from hashes import Hashids def upload_path(instance, filename): # 修正books为字符串常量 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): # 暂存首次创建时上传的thumbnail tmp_thumbnail = None if not self.pk and self.thumbnail: tmp_thumbnail = self.thumbnail self.thumbnail = None # 第一次保存,生成pk super().save(*args, **kwargs) # 生成slug if not self.slug: hashids = Hashids(salt="my salt", min_length=5) self.slug = hashids.encode(self.pk) # 回填暂存的thumbnail if tmp_thumbnail: self.thumbnail = tmp_thumbnail # 关闭force_insert避免报错,第二次保存更新数据 kwargs["force_insert"] = False super().save(*args, **kwargs)
补充说明
- 该方案兼容两种使用场景:创建实例时同步上传缩略图、创建后二次编辑上传缩略图,都能生成正确的存储路径。
- 逻辑完全在模型层实现,不需要修改Django Admin的配置,其他调用该模型保存的接口也能正常生效。
内容的提问来源于stack exchange,提问作者Phil Gyford
相关产品推荐
相关产品推荐

