我在磁盘上有一个现有文件(例如/folder/file.txt),在Django中有一个FileField模型字段。
当我做
instance.field = File(file('/folder/file.txt'))
instance.save()
它将文件另存为file_1.txt
(下次是_2
,等等)。
我知道为什么,但是我不想要这种行为-我知道我想要与该字段关联的文件确实在那里等着我,我只想让Django指向它。
怎么样?
我在磁盘上有一个现有文件(例如/folder/file.txt),在Django中有一个FileField模型字段。
当我做
instance.field = File(file('/folder/file.txt'))
instance.save()
它将文件另存为file_1.txt
(下次是_2
,等等)。
我知道为什么,但是我不想要这种行为-我知道我想要与该字段关联的文件确实在那里等着我,我只想让Django指向它。
怎么样?
Answers:
如果要永久执行此操作,则需要创建自己的FileStorage类
import os
from django.conf import settings
from django.core.files.storage import FileSystemStorage
class MyFileStorage(FileSystemStorage):
# This method is actually defined in Storage
def get_available_name(self, name):
if self.exists(name):
os.remove(os.path.join(settings.MEDIA_ROOT, name))
return name # simply returns the name passed
现在在模型中,使用修改后的MyFileStorage
from mystuff.customs import MyFileStorage
mfs = MyFileStorage()
class SomeModel(model.Model):
my_file = model.FileField(storage=mfs)
FilePathField
或纯文本格式存储文件路径来避免所有这些情况。
只需设置instance.field.name
为文件的路径
例如
class Document(models.Model):
file = FileField(upload_to=get_document_path)
description = CharField(max_length=100)
doc = Document()
doc.file.name = 'path/to/file' # must be relative to MEDIA_ROOT
doc.file
<FieldFile: path/to/file>
MEDIA_ROOT
就是您的相对路径。
doc.file = 'path/to/file'
编写自己的存储类是正确的。但是,get_available_name
这不是重写的正确方法。
get_available_name
当Django看到具有相同名称的文件并尝试获取新的可用文件名时,将调用。不是导致重命名的方法。造成的方法是_save
。中的注释_save
非常好,您可以轻松地找到带有标志的打开待写入文件,os.O_EXCL
如果已经存在相同的文件名,则会引发OSError。Django捕获此错误,然后调用get_available_name
以获取新名称。
所以我认为正确的方法是_save
不带flag覆盖并调用os.open()os.O_EXCL
。修改很简单,但是方法有点长,所以我不在这里粘贴。告诉我您是否需要更多帮助:)
get_available_name
是当你上传同名的文件时,服务器将进入一个死循环。由于_save
检查文件名并决定获取一个新文件,因此get_available_name
仍然返回重复的文件名。因此,您需要同时覆盖两者。
我有完全一样的问题!然后我意识到我的模型是造成这种情况的原因。例如,我有这样的模型:
class Tile(models.Model):
image = models.ImageField()
然后,我希望在磁盘上有更多的磁贴引用相同的文件!我找到的解决方法是将我的模型结构更改为:
class Tile(models.Model):
image = models.ForeignKey(TileImage)
class TileImage(models.Model):
image = models.ImageField()
在意识到这一点之后,这更有意义,因为如果我希望将同一文件保存得更多,那么在数据库中就必须为其创建另一个表!
我想您也可以解决这种问题,只是希望您可以更改模型!
编辑
另外,我猜您可以使用其他存储,例如:SymlinkOrCopyStorage
http://code.welldev.org/django-storages/src/11bef0c2a410/storages/backends/symlinkorcopy.py
您应该定义自己的存储,从FileSystemStorage继承它,并覆盖OS_OPEN_FLAGS
类属性和get_available_name()
方法:
Django版本: 3.1
项目/核心/文件/存储/后端/local.py
import os
from django.core.files.storage import FileSystemStorage
class OverwriteStorage(FileSystemStorage):
"""
FileSystemStorage subclass that allows overwrite the already existing
files.
Be careful using this class, as user-uploaded files will overwrite
already existing files.
"""
# The combination that don't makes os.open() raise OSError if the
# file already exists before it's opened.
OS_OPEN_FLAGS = os.O_WRONLY | os.O_TRUNC | os.O_CREAT | getattr(os, 'O_BINARY', 0)
def get_available_name(self, name, max_length=None):
"""
This method will be called before starting the save process.
"""
return name
在模型中,使用自定义的OverwriteStorage
myapp / models.py
from core.files.storages.backends.local import OverwriteStorage
class MyModel(model.Model):
my_file = model.FileField(storage=OverwriteStorage)
FileField
。每当FileField
保存a时,都会创建该文件的新副本。添加一个选项来避免这种情况非常简单。