python3中用django下载文件,中文名乱码怎么办?

我公司的某个内部系统,用django做的,项目中不可避免地有下载文件的地方,以前偷懒,我都是用django自带的方法,在项目的总urls.py中使用

urlpatterns += static(FILEPATH, document_root=FILEPATH)

这种方法解决。

但是这种方法有个极大的缺陷:测试环境写着玩可以,正式环境肯定要把settings中的debug=True关掉的。而这种方法,在关掉debug之后,就不能用了。

于是我只好走传统线路:设置header。

在urls.py中增加:

url(r"^download/$", views.download, name="download")

在页面中:

<a href="{% url 'download' %}">下载</a>

在views.py中增加一个视图函数:

def download(request):
    return build_download_response(FILE_PATH, "我爱可乐.docx")

(MTV模式的程咬金三板斧,没毛病)

由于系统里面不止一个地方用到下载功能,所以,我把它写成了一个通用的函数:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
from django.http import FileResponse
 
def build_download_response(filepath, filename):
    """
    构建下载文件的文件头
    :param filepath: 文件路径
    :param filename: 文件名
    :return: FileResponse
    """
    absname = os.path.join(filepath, filename) if os.path.isdir(filepath) else filepath
 
    response = FileResponse(open(absname, "rb"))
    response["Content-Type"] = "application/octet-stream"
    response["Content-Disposition"] = "attachment; filename='%s'" % filename
    return response

参照网上的说法,这样是没问题的。蓝鹅,它确实出了问题:当我点击下载按钮的时候,弹出的界面只有“下载”二字。
在这里插入图片描述
喵喵喵?我的文件呢?
我尝试把文件下载下来看了一下,从大小来看,是没有问题的。

在这里插入图片描述
我把名字改过来,可以正常打开,里面没有丢东西——换句话说,只是文件名出了问题。
可是文件名能有毛的问题啊?你不能欺负我公司的人只会中文吧!

简单点说就是,Content-Disposition里面的filename这个东西,原来不是RFC标准,仅支持ASCII编码的文件名。如果文件名不是英文的,恐怕就会出现名字乱码,或者被改名的情况。那么怎么办呢?另一个RFC给加上了扩展,可以定义一个filename*,然后把文件名编码一下。
于是,我把 Content-Disposition 这里从

response["Content-Disposition"] = "attachment; filename='%s'" % filename

改成了

response["Content-Disposition"] = "attachment; filename='%s'; filename*=UTF-8''%s" % (filename.encode("UTF-8"), filename.encode("UTF-8"))
 

结果测试了一下,哭了。
在这里插入图片描述
还真是编码了……
我要闹了。

还好,后来又在 https://segmentfault.com/q/1010000009078463 这篇帖子里找到了答案。原来 filename*=UTF-8’’%s" % filename.encode(“UTF-8”) 这样写是不管用的,django自有django的方法:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
from django.http import FileResponse
from django.utils.encoding import escape_uri_path
 
def build_download_response(filepath, filename):
    """
    构建下载文件的文件头
    :param filepath: 文件路径
    :param filename: 文件名
    :return: FileResponse
    """
    absname = os.path.join(filepath, filename) if os.path.isdir(filepath) else filepath
 
    response = FileResponse(open(absname, "rb"))
    response["Content-Type"] = "application/octet-stream"
    response["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(escape_uri_path(filename))
 
    return response

于是,就可以正常下载了。
在这里插入图片描述
打开看看,内容完全没问题!
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值