You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django FileField读取文件出现编码错误的原因及解决方法

问题

开发阶段使用Django的FileField将文件保存至Mac本地文件系统,通过文件URL可正常下载文件,但通过视图读取时触发编码异常。相关代码如下:

视图代码

def download_database(request, id):
    try:
        project = Project.objects.get(id=id)
        with project.database.open('r') as db:
            response = HttpResponse(
                db.read(), content_type="application/vnd.sqlite3, application/x-sqlite3")
            response['Content-Disposition'] = f'inline; filename={project.database.name}'
            return response
    except Project.DoesNotExist:
        raise Http404

HTML模板代码

<a href="{{ project.database.url }}">Download</a>
<a href="{% url 'download_database' project.id %}">Download</a>

第一种下载方式可正常工作,第二种方式触发错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfb in position 106: invalid start byte

异常栈信息:

Internal Server Error: /project/download_database/54553950-15e5-4ea1-999e-8a6ec2a84ffb
Traceback (most recent call last):
  File "/Users/csabbey/code/survey_server/venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/csabbey/code/survey_server/venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/csabbey/code/survey_server/survey_server/views.py", line 70, in download_database
    db.read(), content_type="application/vnd.sqlite3, application/x-sqlite3")
    ^^^^^^^^^
  File "<frozen codecs>", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfb in position 106: invalid start byte
[15/Jan/2023 20:33:01] "GET /project/download_database/54553950-15e5-4ea1-999e-8a6ec2a84ffb HTTP/1.1" 500 90923

生产环境使用Google Cloud Storage时读取正常,仅本地开发环境出现该问题,求原因及解决方法?

原因分析
  • SQLite文件属于二进制文件,视图中用open('r')文本模式打开时,Django会默认以UTF-8编码尝试解码文件内容,而二进制文件包含非UTF-8的字节序列,直接解码就会触发UnicodeDecodeError。
  • 生产环境的Google Cloud Storage存储后端,在处理文件读取时默认以二进制模式返回字节流,不会进行文本编码解码,因此不会出现异常;本地文件系统的FileField则严格遵循指定的打开模式,文本模式读取二进制文件就会报错。
解决方法

核心是改用二进制模式读取文件,以下两种方案都可以解决问题:

方案一:修改文件打开模式为二进制读

def download_database(request, id):
    try:
        project = Project.objects.get(id=id)
        # 用'rb'模式打开二进制文件,避免编码解码
        with project.database.open('rb') as db:
            response = HttpResponse(
                db.read(), content_type="application/vnd.sqlite3")
            # 文件名用双引号包裹,避免特殊字符导致解析异常
            response['Content-Disposition'] = f'inline; filename="{project.database.name}"'
            return response
    except Project.DoesNotExist:
        raise Http404

方案二:使用Django内置的FileResponse(推荐)

Django提供的FileResponse专门用于文件下载场景,会自动处理二进制流,代码更简洁且不易出错:

from django.http import FileResponse

def download_database(request, id):
    try:
        project = Project.objects.get(id=id)
        # FileResponse自动以二进制模式处理文件
        response = FileResponse(project.database.open('rb'), content_type="application/vnd.sqlite3")
        response['Content-Disposition'] = f'inline; filename="{project.database.name}"'
        return response
    except Project.DoesNotExist:
        raise Http404

额外注意事项

  • Content-Disposition中的文件名建议用双引号包裹,避免文件名包含空格、中文或特殊字符时出现浏览器解析错误。
  • 统一使用二进制模式读取文件,可以消除本地开发环境和生产环境存储后端的行为差异,保证代码一致性。

内容的提问来源于stack exchange,提问作者Crag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:25:16