我第一次尝试生产部署Django项目。我的Django之前的实现包含了相当多的数据(数千个图像,数据库中有数千个条目)。我编写了一个自定义manage.py populate_db
命令,用于解析旧数据库的转储,并根据我的模型创建新的Django数据库。但是我坚持添加所有文件。
我的初始部署计划是在本地创建一次数据库,sFTP将所有图像上传到服务器上的媒体文件夹,对数据库执行相同的操作。为此,我需要数据库来引用媒体文件夹中的图像文件。据我所知,Django只是通过文件名来做。到目前为止,我已经能够做到这一点:
def _add_image_files(self, user: str):
i = 0
for f in local_files:
i += 1
photo = Photo(album=1, number=i, back=False, added_by=user)
from django.core.files import File
photo.image.save(f.name, File(open(f.path, 'rb')))
其中Photo定义为
class Photo(models.Model):
album = models.IntegerField(null=True)
number = models.IntegerField(null=True)
image = models.ImageField(null=True, upload_to='photo_image_files')
然而,Django显然通过读取和写入媒体文件夹来复制每个文件。我不需要这种重复,我只想将每个文件的引用添加到数据库中。
我怎样才能实现它?或者,如果由于某种原因这是一个糟糕的方法,请告诉我一个更好的方法。感谢。
答案 0 :(得分:0)
I have actually found the answer here: https://stackoverflow.com/a/12917845/674976 The "trick" is that ImageField can be simply populated with the image file name. Combined with bulk_create, I now get a reasonable execution time.
photo_list = []
for i in range(1000):
photo = Photo(album=1, number=i, back=False)
photo.image = 'photo_image_files/:filename_i.jpg'
photo_list.append(photo)
Photo.objects.bulk_create(photo_list)
I couldn't find any reference for this trick (assigning file name directly to ImageField), so if you could add one by editing or in comments, it would be a nice improvement to this answer.
答案 1 :(得分:0)
django 版本:3.2.4
好吧,你可以定义你的存储,它不会复制文件,如果它已经存在。 警告:当 2 个进程尝试保存同名文件时,此解决方案会导致问题。但它适合以编程方式填充数据库。
models.py
...
from django.core.files.storage import FileSystemStorage
...
class NonDuplicateStorage(FileSystemStorage):
OS_OPEN_FLAGS = os.O_WRONLY | os.O_CREAT | getattr(
os, 'O_BINARY', 0)
def exists(self, name):
return False
non_duplicate_storage = NonDuplicateStorage()
class Photo(models.Model):
...
image = models.ImageField(null=True, upload_to='photo_image_files', storage = non_duplicate_storage)
这里发生了什么: 让我们打开存储类
Lib\site-packages\django\core\files\storage.py
class FileSystemStorage(Storage):
"""
Standard filesystem storage
"""
# The combination of O_CREAT and O_EXCL makes os.open() raise OSError if
# the file already exists before it's opened.
OS_OPEN_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(
os, 'O_BINARY', 0)
def _save(self, name, content):
...
# There's a potential race condition between get_available_name and
# saving the file; it's possible that two threads might return the
# same name, at which point all sorts of fun happens. So we need to
# try to create the file, but if it already exists we have to go back
# to get_available_name() and try again.
...
while True:
...
fd = os.open(full_path, self.OS_OPEN_FLAGS, 0o666)
...
except FileExistsError:
# A new name is needed if the file exists.
name = self.get_available_name(name)
...
和 self.get_available_name 调用 self.exists(), case 文件已经存在 - 将重命名