【问题标题】:Enforce unique upload file names using django?使用 django 强制执行唯一的上传文件名?
【发布时间】:2010-04-20 08:30:56
【问题描述】:

使用 django 在服务器上使用唯一文件名重命名照片的最佳方法是什么?我想确保每个名称只使用一次。是否有任何 pinax 应用程序可以做到这一点,也许使用 GUID?

【问题讨论】:

  • 你需要一个 python 库来重命名文件,所以它们是独一无二的?
  • 查看@mlissner 的回答。使用默认 Storage 类的文件现在将自动生成唯一名称,不再需要用户代码。见get_available_name
  • Django 默认已经这样做了。只需将所有图像命名为“image.jpg”,从第二张开始,它们将自动命名为:image_XpmEQxy.jpg

标签: python django pinax file-rename


【解决方案1】:

使用 uuid。要将其与您的模型联系起来,请参阅 Django documentation 获取 FileField upload_to。

例如,在您的 models.py 中定义以下函数:

import uuid
import os

def get_file_path(instance, filename):
    ext = filename.split('.')[-1]
    filename = "%s.%s" % (uuid.uuid4(), ext)
    return os.path.join('uploads/logos', filename)

然后,在定义 FileField/ImageField 时,将 get_file_path 指定为 upload_to 值。

file = models.FileField(upload_to=get_file_path,
                        null=True,
                        blank=True,
                        verbose_name=_(u'Contact list'))

【讨论】:

  • 这样做是一个错误的决定,因为您将在此字段上进行无限迁移,因为在每次迁移时您将有不同的上传路径。
  • @Creotiv 这不会更改上传路径,而是将文件名替换为 UUID。这不会导致任何迁移问题。
  • @Hybrid 是的,但是每次迁移时,目录路径都会不同,因此迁移系统会认为该字段已更改。
  • @Creotiv - 不,迁移仅跟踪如何生成文件名。这意味着迁移知道正在使用一个名为get_file_path 的函数。如果使用了upload_to=uuid4(),那么您所说的问题就会发挥作用。
  • 得到NameError: name 'get_file_path' is not defined :(
【解决方案2】:

更好的方法是在你的 helpers.py 中使用一个公共类。这样您就可以在您的应用中重复使用随机文件生成器。

在你的 helpers.py 中:

import os
import uuid
from django.utils.deconstruct import deconstructible


@deconstructible
class RandomFileName(object):
    def __init__(self, path):
        self.path = os.path.join(path, "%s%s")

    def __call__(self, _, filename):
        # @note It's up to the validators to check if it's the correct file type in name or if one even exist.
        extension = os.path.splitext(filename)[1]
        return self.path % (uuid.uuid4(), extension)

然后在你的模型中导入帮助类:

from mymodule.helpers import RandomFileName 

然后使用它:

logo = models.ImageField(upload_to=RandomFileName('logos'))

参考:https://coderwall.com/p/hfgoiw/give-imagefield-uploads-a-unique-name-to-avoid-file-overwrites

【讨论】:

    【解决方案3】:

    在 Django 1.6.6、1.5.9 和 1.4.14 之前,get_avaialable_name 函数会通过添加下划线自动为文件赋予唯一名称。因此,例如,如果您将一个文件“test.jpg”然后将另一个文件“test.jpg”保存到您的服务器,第一个文件将被称为 test.jpg,第二个文件将被称为 test_1.jpg。

    唉,这原来是对机器进行 DDOS 攻击的向量,通过向其发送数千个零字节文件进行存储,每个文件检查数千个以前的文件以查看其名称应该是什么。

    正如您将see in the docs 一样,新系统会在下划线后附加七个随机数字来解决此问题。

    【讨论】:

      【解决方案4】:

      在撰写此答案时,您似乎不再需要做任何特别的事情来实现这一点。如果你用静态upload_to属性设置FileField,Django存储系统会自动管理命名,这样如果上传了重复的文件名,Django会为重复的文件随机生成一个新的唯一文件名。

      适用于 Django 1.10。

      【讨论】:

      • 确认这在 Django 2.1 中仍然有效。这是在默认存储类中自动完成的。见get_available_name
      • 适用于 django 3.1
      【解决方案5】:

      您可以编写自己的FileField 并改写generate_filename

      例如:

      class UniqueNameFileField(FileField):
          def generate_filename(self, instance, filename):
              _, ext = os.path.splitext(filename) 
              name = f'{uuid.uuid4().hex}{ext}'
              return super().generate_filename(instance, name)
      

      【讨论】:

        【解决方案6】:

        如何将文件名与上传照片的日期/时间连接起来,然后使用hashlib 创建消息摘要?这应该给你唯一的文件名。

        或者,您可以重新使用 a neat little snippet 创建唯一文件名,然后使用该文件的完整路径作为哈希调用的输入。这为您提供了唯一的恒定长度字符串,您可以将其映射到您的文件。

        【讨论】:

        • 但是,同一时间怎么做同名呢?
        • 您可以将可用磁盘空间量添加到哈希字符串中 - 当您上传新文件时应该始终更改。
        • @zjm1126 @Jon Cage 你可以发明各种方法让它更有可能是独一无二的,但基本上总会有某种碰撞概率,这个想法只是为了减少它概率到可接受的数量,然后在发生时处理
        • 确实如此。不过,我链接到的 sn-p 确实是独一无二的;文件系统将保证只能创建一个具有相同名称的文件。因此,在完整的路径上创建一个 has 应该是相当不错的。
        【解决方案7】:

        django 自动强制执行唯一的文件名。 如果文件已经存在,则在文件名后附加七个唯一字符

        在 django 2.2 上测试

        【讨论】:

          猜你喜欢
          • 2011-06-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-08
          • 1970-01-01
          • 2010-09-10
          • 2015-11-18
          • 1970-01-01
          相关资源
          最近更新 更多