如何用Django和boto3下载AWS S3文件?遇问题求助
解决Django中付费用户下载AWS S3文件的问题
一、修复FileResponse方法的AttributeError错误
原代码直接使用open(file, 'rb')读取文件是错误的——当Django用AWS S3作为存储后端时,obj.file是S3存储的文件对象,并非本地文件,Python内置open()无法直接读取。
修改views.py的下载函数:
def download_file(request, id, order_id): obj = Product.objects.get(id=id) order = Order.objects.get(order_id=order_id) # 先完成订单有效性校验(如确认已支付、用户匹配等) file_stream = obj.file.open('rb') response = FileResponse(file_stream) # 设置响应头触发浏览器下载动作 response['Content-Disposition'] = f'attachment; filename="{obj.file.name.split("/")[-1]}"' response['Content-Type'] = 'application/octet-stream' return response
核心说明:
obj.file.open('rb')通过Django的S3存储后端直接获取文件二进制流,无需本地缓存- 添加
Content-Disposition头可强制浏览器弹出下载框,而非直接打开文件
二、修复boto3预签名URL的NoSuchKey错误
问题原因
错误提示Key: files/it_report_edited.docx不存在,说明你传入的S3文件Key与实际存储路径不符。通常Django配置S3时,文件会自动添加media/前缀,实际Key应为media/files/it_report_edited.docx。
修复代码
def download_file(request, id, order_id): obj = Product.objects.get(id=id) order = Order.objects.get(order_id=order_id) # 订单有效性校验(必须步骤) client = boto3.client( 's3', aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'), aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY') ) bucket_name = os.environ.get('AWS_STORAGE_BUCKET_NAME') # 从Django存储后端获取文件的实际S3 Key(自动适配配置的前缀) file_key = obj.file.storage.object_name(obj.file.name) url = client.generate_presigned_url( 'get_object', Params={'Bucket': bucket_name, 'Key': file_key}, ExpiresIn=600 ) return HttpResponseRedirect(url)
额外检查项
- 登录AWS S3控制台确认文件的实际Key,是否包含
media/前缀 - 检查Django的S3配置是否正确:
# settings.py示例 AWS_STORAGE_BUCKET_NAME = '你的存储桶名称' AWS_LOCATION = 'media' DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' - 确保boto3使用的IAM用户拥有
s3:GetObject权限
两种方法的适用场景
- FileResponse方法:适合需要在Django层处理文件流的场景(如添加自定义校验、修改文件内容),但会占用服务器带宽和内存
- 预签名URL方法:更高效,直接引导用户从S3下载,减轻Django服务器压力,适合大文件下载
内容的提问来源于stack exchange,提问作者Quest
相关产品推荐
相关产品推荐

