You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何将一个FileField的文件复制到另一个不同上传路径的FileField?

解决Django FileField自动备份文件的问题

我来帮你搞定这个文件备份的问题!你当前的代码只是把attachment_number的文件路径赋值给了attachment_copy,但并没有实际将文件内容复制到备份存储的目录下——Django的FileField不会自动帮你复制文件,得手动处理文件的读写操作才行。

步骤1:优化模型的存储路径(可选但建议)

你现在的UPLOAD_ROOT和UPLOAD_COPY都是C:/,这会导致源文件和备份文件混在同一个根目录,容易混乱。建议改成不同的独立路径:

class MyModal(models.Model):
    UPLOAD_ROOT = "C:/uploads/"
    UPLOAD_COPY = "C:/uploads_backup/"
    upload_storage = FileSystemStorage(location=UPLOAD_ROOT, base_url="/uploads")
    upload_storage_copy = FileSystemStorage(location=UPLOAD_COPY, base_url="/uploads_backup")
    
    # 其他字段保持不变...

另外,你的file_path_dir_copy函数生成的路径有点冗余(会出现FileBackUp/FileBackUp2024.05.20/xxx这种嵌套),可以简化一下:

def file_path_dir_copy(instance, filename):
    # 只保留日期作为子目录,路径更简洁
    return "FileBackUp/{0}/{1}".format(datetime.now().strftime("%Y.%m.%d"), filename)

步骤2:修改save_model方法,实现真实文件复制

核心逻辑是读取源文件的内容,然后写入到备份存储系统中。替换你当前的save_model方法:

import os
from django.core.files.base import ContentFile

def save_model(self, request, obj, *args, **kwargs):
    # 先检查源文件是否存在,避免空文件报错
    if obj.attachment_number and obj.attachment_number.file:
        # 获取源文件的纯文件名
        filename = os.path.basename(obj.attachment_number.name)
        # 调用upload_to函数生成备份文件的目标路径
        backup_path = file_path_dir_copy(obj, filename)
        # 读取源文件的二进制内容
        with obj.attachment_number.open('rb') as source_file:
            file_content = source_file.read()
            # 将内容写入备份字段,save=False避免提前触发模型保存
            obj.attachment_copy.save(backup_path, ContentFile(file_content), save=False)
    # 调用父类方法完成最终的模型保存
    super().save_model(request, obj, *args, **kwargs)

代码说明:

  • 先判断attachment_number是否有有效文件,防止空指针异常。
  • 使用with语句读取源文件,确保文件资源能自动释放。
  • 通过obj.attachment_copy.save()主动将文件内容写入备份存储,这一步才是真正完成文件复制的关键。

额外适配:处理多实例场景(如果用了FormSet)

如果你的obj是FormSet返回的多个实例集合,需要调整循环逻辑确保每个对象都被处理:

def save_model(self, request, obj, *args, **kwargs):
    # 判断是否为多实例集合
    if hasattr(obj, '__iter__'):
        for sub_obj in obj:
            if sub_obj.attachment_number and sub_obj.attachment_number.file:
                filename = os.path.basename(sub_obj.attachment_number.name)
                backup_path = file_path_dir_copy(sub_obj, filename)
                with sub_obj.attachment_number.open('rb') as source_file:
                    file_content = source_file.read()
                    sub_obj.attachment_copy.save(backup_path, ContentFile(file_content), save=False)
    else:
        # 单个实例的处理逻辑
        if obj.attachment_number and obj.attachment_number.file:
            filename = os.path.basename(obj.attachment_number.name)
            backup_path = file_path_dir_copy(obj, filename)
            with obj.attachment_number.open('rb') as source_file:
                file_content = source_file.read()
                obj.attachment_copy.save(backup_path, ContentFile(file_content), save=False)
    super().save_model(request, obj, *args, **kwargs)

最后要注意:确保你的存储目录(C:/uploads/和C:/uploads_backup/)已经存在,并且Django进程有读写权限,否则会抛出文件操作错误。

内容的提问来源于stack exchange,提问作者Dhia Shalabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 07:42:39