如何在Django视图中实现从S3下载文件的功能
Django实现S3文件下载的解决方案
核心思路
你现有的函数依赖本地文件路径读取文件,但S3上的对象没有本地存储路径,不需要走本地IO逻辑,直接调用S3的SDK读取对象流或者生成临时访问链接即可实现需求。
前置准备
- 安装AWS官方SDK:
pip install boto3 - 在Django settings中配置S3凭证(生产环境推荐通过IAM角色、环境变量传递凭证,不要硬编码密钥):
# settings.py AWS_ACCESS_KEY_ID = "你的S3访问密钥ID" AWS_SECRET_ACCESS_KEY = "你的S3秘密访问密钥" AWS_S3_REGION_NAME = "你的S3区域,例如ap-beijing" AWS_STORAGE_BUCKET_NAME = "你的S3存储桶名称"
方案1:Django代理下载(适配原函数逻辑)
和你现有写法逻辑一致,Django先从S3拉取文件流再返回给客户端,适合小文件场景:
import boto3 from django.conf import settings from django.http import HttpResponse, Http404 def download(request): # 初始化S3客户端 s3 = boto3.client( 's3', aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_S3_REGION_NAME ) s3_file_key = "S3上的文件路径,例如docs/2024/订单.pdf" base_name_edi = "用户下载时展示的文件名,例如2024年6月订单.pdf" try: # 直接从S3获取文件对象 s3_response = s3.get_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=s3_file_key) # 读取S3返回的文件流生成响应,无需存本地 response = HttpResponse(s3_response['Body'].read()) # 保持原有响应头配置 response['Content-Disposition'] = f'inline; filename={base_name_edi}' # 可选:设置正确的文件类型,避免下载时格式识别错误 response['Content-Type'] = s3_response['ContentType'] return response except s3.exceptions.NoSuchKey: raise Http404("请求的文件不存在")
方案2:S3预签名URL下载(推荐,节省服务器资源)
大文件场景优先选用该方案,不需要Django转发文件流,直接生成有时效性的S3临时访问链接,让客户端直接跳转下载,大幅降低服务器带宽消耗:
import boto3 from django.conf import settings from django.shortcuts import redirect def download(request): s3 = boto3.client( 's3', aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_S3_REGION_NAME ) s3_file_key = "S3上的文件路径,例如docs/2024/订单.pdf" base_name_edi = "用户下载时展示的文件名,例如2024年6月订单.pdf" # 生成有效期为3600秒(1小时)的预签名下载链接 presigned_url = s3.generate_presigned_url( ClientMethod='get_object', Params={ 'Bucket': settings.AWS_STORAGE_BUCKET_NAME, 'Key': s3_file_key, 'ResponseContentDisposition': f'inline; filename={base_name_edi}' }, ExpiresIn=3600 ) # 直接重定向到S3临时链接即可完成下载 return redirect(presigned_url)
注意事项
- 如果你使用的是阿里云OSS、腾讯云COS等兼容S3协议的对象存储,只需要在初始化s3客户端时加上
endpoint_url参数指定服务地址即可,其余逻辑完全通用 - 预签名URL的有效期可根据业务需求调整,使用IAM用户签名的情况下最长不超过7天
内容的提问来源于stack exchange,提问作者Rikky Bhai
相关产品推荐
相关产品推荐

