Django将requests下载文件存FileField时出现AttributeError:_committed报错
问题原因
Django的FileField不支持直接传入Python原生文件对象,它要求传入django.core.files.File类或其子类的实例,这类实例内置_committed属性用于标记文件是否已同步到存储后端,你代码中直接传入了原生_io.BufferedWriter对象,缺少该属性触发报错。
解决方案
步骤1:导入Django内置File类
在mp3.py头部的导入区域添加以下导入语句:
from django.core.files import File
步骤2:修改save_mp3方法逻辑
调整写入文件后包装文件对象再传入模型创建方法,修改后代码如下:
def save_mp3(): """ Save the downloaded file to the filesystem and local database. """ with open(filepath, 'xb') as f: content = response.content for i in range(0, len(content), MP3.block_size): upper = min(i + MP3.block_size, len(content)) f.write(content[i:upper]) # 关闭写入句柄后,用Django File类包装本地文件 with open(filepath, 'rb') as f: mp3_file = File(f, name=f"{id}.mp3") return cls.get_queryset().create(id=id, data=mp3_file)
额外优化(可选)
创建完模型实例后可以删除临时目录下的源文件,避免占用磁盘空间:
def save_mp3(): """ Save the downloaded file to the filesystem and local database. """ with open(filepath, 'xb') as f: content = response.content for i in range(0, len(content), MP3.block_size): upper = min(i + MP3.block_size, len(content)) f.write(content[i:upper]) try: with open(filepath, 'rb') as f: mp3_file = File(f, name=f"{id}.mp3") return cls.get_queryset().create(id=id, data=mp3_file) finally: # 清理临时文件 if os.path.exists(filepath): os.remove(filepath)
注意事项
你当前MP3Manager的get_mp3方法使用了@classmethod装饰器,直接调用cls.get(id=id)属于错误用法:Manager类的查询方法需要绑定模型的查询集才能执行,更规范的写法是移除@classmethod装饰器,改为普通管理器方法,直接通过self调用查询/创建方法:
# 移除@classmethod装饰器,改为实例方法 def get_mp3(self, id, url): # 原有逻辑不变 try: # 直接用self调用get方法 mp3 = self.get(id=id) except MP3.DoesNotExist: # 其余逻辑不变 ... def save_mp3(): ... # 直接用self.create创建实例 return self.create(id=id, data=mp3_file)
内容的提问来源于stack exchange,提问作者Matt McCarthy
相关产品推荐
相关产品推荐

