Django ImageField/FileField 使用模型的主键保存上传文件

1 投票
2 回答
3862 浏览
提问于 2025-04-17 04:44

我正在把一个老旧的网站(最初是用rails写的)进行转换,默认情况下,图片是以{{pk}}.{{extension}}的格式保存的,每当上传新文件时,原来的文件总是会被覆盖。我想在这个django版本中继续使用这个格式。

我最开始以为扩展FileSystemStorage会是个好办法,但我不知道怎么把当前的模型对象传递给它。有没有人能给我一些“django方式”的建议来实现这个?

如果我需要写一个自己的类来扩展ImageField来管理这个,那也没问题。:) 只是想知道我是不是漏掉了什么简单的东西。

[编辑] 根据surfeurxDrTyrsa的回答,我做了以下修改:

temp_image = None

def image_path(self, uploaded_file_name):
    prefix = 'designs/'
    extension = os.path.splitext(uploaded_file_name)[-1]
    if self.pk != None:
        return prefix + str(self.pk) + extension
    else:
        tmp_name = str(uuid.uuid4())
        self.temp_image = prefix + tmp_name + extension
        return self.temp_image

image_upload = models.ImageField(upload_to=image_path, null=True, blank=True) 

def save(self):
    self.updated_at = datetime.now()

    is_new = self.pk == None
    super(Design, self).save()

    if is_new:
        if self.temp_image != None:
            os.rename(MEDIA_ROOT + self.temp_image, MEDIA_ROOT + self.image_path(self.temp_image))
            self.temp_image = None

我现在面临的真正问题是,我希望它能覆盖原来的图片。这会提供正确的文件名,但看起来我必须扩展ImageField才能实现覆盖。我找到这个小东西:http://djangosnippets.org/snippets/636/

2 个回答

3

你需要定义一个叫做 upload_to 的函数。这个函数会接收一个叫做 instance 的参数。不过要记住,如果你是在 创建 这个实例的时候,它还没有 pk(主键)值(不过你可以先保存这个实例,然后再保存图片)。

3

你可以像下面这样使用 upload_to:

def image_path(instance, filename):
    return instance.id + os.path.splitext(filename)[1]

class Brand(models.Model):
    ...
    logo = models.ImageField(upload_to=image_path, null=True, blank=True)

撰写回答