Django上传文件到AWS S3报ValueError: Filename must be a string如何解决
问题原因
你调用的boto3 S3客户端的upload_file()方法,第一个入参要求是本地文件的路径字符串,而非文件句柄对象。你代码中传入了open(img_path, 'rb')得到的文件对象fp,不符合方法入参要求,因此触发ValueError: Filename must be a string报错。
解决方案
提供两种可选修复方式,按需选择即可:
方案1:直接传入本地文件路径(推荐,代码更简洁)
你已经将图片保存到了本地路径img_path,无需额外打开文件,直接将路径作为第一个参数传入upload_file()即可,修改对应代码段为:
try: # 删掉原有with open打开文件的逻辑,直接传本地路径字符串 response = s3_client.upload_file(img_path, 'etp-tms', 'image_0.jpg') except ClientError as e: print(e)
方案2:替换为支持文件对象的上传方法
如果你确实需要通过文件句柄上传,将方法替换为upload_fileobj()即可,该方法支持传入文件对象作为第一个参数:
try: with open(img_path, 'rb') as fp: # 把upload_file改为upload_fileobj response = s3_client.upload_fileobj(fp, 'etp-tms', 'image_0.jpg') except ClientError as e: print(e)
额外优化建议
如果你的业务不需要在服务器本地留存图片备份,可以直接省略写入本地磁盘的步骤,直接将Django拿到的上传文件对象传入S3,性能更高:
def save_pic(request): print("save_pic") data = {'state': 0} if request.method == 'POST': image = request.FILES.get('image') if not image: return JsonResponse(data) import boto3 from botocore.exceptions import ClientError s3_client = boto3.client('s3', aws_access_key_id='XXX', aws_secret_access_key='XXX', region_name='XXX') try: # 直接上传文件对象,无需本地存盘,可自定义S3端存储的文件名 s3_client.upload_fileobj(image, 'etp-tms', f'image_{image.name}') data['state'] = 1 except ClientError as e: print(e) return JsonResponse(data) return JsonResponse(data="fail", safe=False)
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

