手动将文件添加到Django的媒体文件夹,并以编程方式填充数据库

时间:2016-12-09 00:01:18

标签: django database

我第一次尝试生产部署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显然通过读取和写入媒体文件夹来复制每个文件。我不需要这种重复,我只想将每个文件的引用添加到数据库中。

我怎样才能实现它?或者,如果由于某种原因这是一个糟糕的方法,请告诉我一个更好的方法。感谢。

2 个答案:

答案 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 文件已经存在 - 将重命名