【问题标题】:Manually add files to Django's media folder and programmatically populate the database手动将文件添加到 Django 的媒体文件夹并以编程方式填充数据库
【发布时间】:2017-04-24 09:00:42
【问题描述】:

我第一次尝试生产部署一个 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')))

照片定义为

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

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

【问题讨论】:

    标签: django database


    【解决方案1】:

    我实际上在这里找到了答案: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),所以如果你可以通过编辑或在 cmets 中添加一个,这将是对这个答案的一个很好的改进。

    【讨论】:

      【解决方案2】:

      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(), 案例文件已经存在 - 它将被重命名

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-19
        • 2014-06-11
        • 1970-01-01
        • 2016-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多