Django FileField.save() 生成重复文件

2 投票
1 回答
3159 浏览
提问于 2025-04-17 09:05

我有一些用户提交的内容,想把它写入一个文件,然后保存到一个叫做 FileField 的地方。

我有一个 模型,它看起来是这样的:

class Revision(models.Model):
    def custom_revision_file_path(instance, filename):
        return '/'.join(['content/revisions', filename])
    path = models.FileField(upload_to=custom_revision_file_path)
    document = models.ForeignKey(Document)
    ...

而创建这个实例的 视图 是这样的:

def handle_revisions(request): 
    document = Document.objects.get(id=request.GET['docid'])
    basename = os.path.basename(str(document.path))

    revision = Revision.objects.create(
        document = document,
    )
    revision.path.save(basename, ContentFile(request.GET['revision']))

整体上这些都能正常工作,但有两个问题:

1) ContentFile 在我的字符串每个字母之间加了一个空格,所以 'test' 变成了 't e s t'

2) 不知道为什么,每次运行这个视图时,都会保存两个 Revision 实例,它们的路径差不多。比如,一个路径是 'content/revisions/test.txt',另一个是 'content/revisions/test_1.txt',而第二个本来就不应该存在。

这是怎么回事呢?

1 个回答

3

首先,你绝对不应该用那种方式来创建路径:

'/'.join(['content/revisions', filename])

而是应该这样:

os.path.join("my_dir", "my_subdir", ..., "filename.txt")

你不需要知道你的应用是运行在类Unix系统还是Windows上(没错,有些人用Windows作为网页服务器)。

另外,你不应该把你的FileField属性叫做path,这样会让人困惑,因为它和FilePathField的名字很像。

这个字段是NOT NULL吗?因为在你的create()语句里你没有提供一个值。这应该会引发一个错误。

我不太明白这个:

revision.path.save(basename, ContentFile(request.GET['revision']))

你想要实现什么?你确定要把一个GET参数存储在文件里吗?

为了回答你的问题,默认情况下,Django不会自动覆盖你文件系统中已经存在的文件,这就是为什么它会自动用一个唯一的路径来存储文件,并添加一个后缀。

如果这种行为不符合你的需求,可以考虑写一个自定义文件存储

撰写回答