我试图第一次尝试生产django项目。我的django pre-django实现包含大量数据(数千个图像,数据库中的数千个条目)。我写了一个自定义manage.py populate_db
命令,该命令解析了旧数据库的转储,并根据我的模型创建新的Django数据库。但是,我坚持添加所有文件。
我的最初部署计划是在本地创建一次数据库,SFTP-UPLOAD所有图像到服务器上的媒体文件夹,对数据库进行相同的操作,仅此而已。为此,我需要数据库在媒体文件夹中引用图像文件。据我了解,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')))
将照片定义为
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显然通过读取并将其写入媒体文件夹来重复每个文件。我不需要此重复,我只想将每个文件的引用添加到数据库中。
我该如何实现?另外,如果这是出于某种原因的方法,请让我知道更好的方法。谢谢。
我实际上在这里找到了答案:https://stackoverflow.com/a/12917845/674976"窍门"是可以简单地用图像文件名填充imageField。结合Bulk_create,我现在得到合理的执行时间。
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)
我找不到此技巧的任何参考(将文件名直接分配给ImageField),因此,如果您可以通过编辑或评论中添加一个技巧,这将是一个很好的改进。
django版本:3.2.4
好吧,您可以定义您的存储空间,这不会重复文件,情况已经存在。警告:此解决方案会导致问题,当两个进程尝试以相同名称保存文件时。但它适合编程填充数据库。
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 storege.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(),案例文件已经存在 - 它将被重命名