在 Django 中保留 FileField 的原始文件名

Posted

技术标签:

【中文标题】在 Django 中保留 FileField 的原始文件名【英文标题】:Keeping Original Filename for FileField in Django 【发布时间】:2014-12-30 22:14:42 【问题描述】:

我想在 Django 中保留 UploadedFile 的原始文件名,其位置存储在 FileField 中。现在我观察到,如果两个文件具有相同的名称,则上传的第一个文件保留其原始名称,但第二次上传具有该名称的文件时,它会附加一个随机字符串以使文件名唯一。一种解决方案是在模型中添加一个附加字段:Django: How to save original filename in FileField? 或 Saving Original File Name in Django with FileField,但这些解决方案似乎不是最理想的,因为它们需要更改 Model 字段。

另一种方法是在文件前面添加一个随机目录路径,确保在给定目录中文件名是唯一的,并允许basename 保持不变。一种方法是传递一个可调用的upload_to,它就是这样做的。另一种选择是继承 FileField 并覆盖 get_filename 以不将输入文件名剥离到 basename 允许调用者传入带有前置路径的文件名。如果我想使用ImageField,后一个选项并不理想,因为我也必须对其进行子类化。

【问题讨论】:

【参考方案1】:

在查看the code that actually generates the unique filename by appending the random string 时,看起来这个问题的最佳解决方案可能是使用subclass the Storage class in-use 和override get_available_name 方法来创建唯一的文件名,方法是在目录之前添加一个目录,而不是将字符串添加到基本名称。

【讨论】:

【参考方案2】:

很抱歉快速回答,这是解决您问题的另一种方法: 这里的想法是为每个上传的文件创建一个唯一的文件夹。

# in your settings.py file
MY_FILE_PATH = 'stored_files/'

您的文件将被存储的路径:/public/media/stored_files

# somewhere in your project create an utils.py file
import random
try:
    from hashlib import sha1 as sha_constructor
except ImportError:
    from django.utils.hashcompat import sha_constructor


def generate_sha1(string, salt=None):
    """
    Generates a sha1 hash for supplied string.

    :param string:
        The string that needs to be encrypted.

    :param salt:
        Optionally define your own salt. If none is supplied, will use a random
        string of 5 characters.

    :return: Tuple containing the salt and hash.

    """
    if not isinstance(string, (str, unicode)):
         string = str(string)
    if isinstance(string, unicode):
        string = string.encode("utf-8")
    if not salt:
        salt = sha_constructor(str(random.random())).hexdigest()[:5]
    hash = sha_constructor(salt+string).hexdigest()

    return (salt, hash)

在你的 models.py 中

from django.conf import settings
from utils.py import generate_sha1

def upload_to_unqiue_folder(instance, filename):
    """
    Uploads a file to an unique generated Path to keep the original filename
    """

    salt, hash = generate_sha1(''.format(filename, get_datetime_now().now))

    return '%(path)s%(hash_path)s%(filename)s' % 'path': settings.MY_FILE_PATH,
                                               'hash_path': hash[:10],
                                               'filename': filename



#And then add in your model fileField the uplaod_to function
class MyModel(models.Model):
    file = models.FileField(upload_to=upload_to_unique_folder)

文件将上传到这个位置:

public/media/stored_file_path/unique_hash_folder/my_file.extention

注意:我从Django userena 来源获得了代码,并根据我的需要对其进行了调整

注意2:有关更多信息,请查看有关 Django 文件上传的这篇精彩帖子:File upload example

祝你有美好的一天。

编辑:试图提供一个可行的解决方案:)

【讨论】:

这只有在两个同名文件没有在同一日期上传时才有效。 用其他解决方案为您的案例编辑了我的回答,没有测试它,但它应该可以工作【参考方案3】:

据我了解,在表单提交/文件上传过程中,可以添加表单验证功能。

在验证和清理过程中,您可以检查数据库是否没有重复名称(即查询该文件名是否存在)。

如果它是重复的,你可以把它重命名为 xyz_1、xyz_2 等

【讨论】:

参考this 问题是这是在名称后面附加一个字符串。我必须把它剥掉才能备份它。另外我怎么知道第一个文件是否已经以下划线结尾,然后是数字?我也得逃跑。 例如,您可以在文件名前附加或附加时间戳(例如:xyz_20140101121259)。一个以毫秒为单位的时间戳,你确切地知道这个时间戳的长度,所以当你备份它时很容易把它去掉 这几乎一直都很好,但同样不能保证不会在同一毫秒内上传两个文件。 如果您对此非常担心,请执行 20140101121259001、20140101121259002 等。

以上是关于在 Django 中保留 FileField 的原始文件名的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 的 FileField 中保存来自传入电子邮件的附件?

Django:在编辑模型时自定义 FileField 值

如何在 Django 中使用 FileField 测试表单?

使用 model.FileField 在 Django 中保存之前修改文件名

Django:在编辑模型时自定义FileField值

使用 FileField 在 Django 中保存原始文件名