首页 > 解决方案 > 为什么 Django FieldFIle readline() 返回文本文件的十六进制版本?

问题描述

有一个奇怪的问题。

我有一个 Django 应用程序,它打开一个文件(表示为 Django )并使用如下方式FieldFile读取每一行:readline()

with file.open(mode='r') as f:
  row = f.readline()
  # do something with row...

该文件是文本,utf-8 编码,行以\r\n.

问题是每一行都被读取为字符串的十六进制表示,所以我得到的是“48656c6c6f”而不是“Hello”。

一些奇怪的事情:

对为什么这之前有效以及我做错了什么而摸不着头脑。

环境是在 Docker 容器中运行的 Python 3.8、Django 2.2.8 和 3.0(结果相同)。

编辑

让我指出,解决这个问题只是使用

row = f.readline().decode()

但我仍然想弄清楚发生了什么。

编辑 2

除此之外, FieldFile.open() 将文件作为二进制文件读取,而普通 Python open() 将文件作为文本文件读取。

标签: pythondjangobotoreadline

解决方案


这似乎很奇怪。我想你会在尝试关注后立即看到解决方案(如果它真的无助于找到它,我会更新我的答案或删除它,但我很有信心)

假设有一些代码,即monkeypatching file.open 或django view 函数。

我的建议是:

使用 manage.py runserver 开始您的代码 将以下代码添加到 manage.py (作为第一行

import file
print("ID of file.open at manage startup is", id(file.open)

然后将代码直接添加到视图上方的一行file.open

    print("ID of file.open before opening is", id(file.open)

如果两个 id 不同,那么某些东西会修补您的打开功能。如果两者相同,那么问题一定出在其他地方。

如果您没有看到这两个打印的输出,则可能是某些东西打断了您的视图。

如果这不起作用,请尝试使用 open()而不是file.open()

你使用有什么特别的原因吗file.open()

附录 1:

所以你说的是,那个文件是一个类的对象实例,它是一个 FileField 吗?在任何情况下,您都可以获得文件的名称并以正常open()方式打开它,看看它是否只是file.open()做有趣的事情,或者它是否也在open()以这种奇怪的方式读取它。您是否刚刚从命令行打开文件cat filename(或者如果在 Windows 下使用type filename?

如果这不起作用,我们可以添加跟踪以跟踪正在执行的源代码的每一行。

附录 2:

那么如果你不能在 a 中尝试这个,manage.py runserver如果你尝试用 a 读取文件会发生什么manage.py shell

只需打开 shell 并输入如下内容:

from <your_application>.models import <YourModel>
entry = <YourModel>.objects.get(id=<idofentry>)
line1 = entry.<filefieldname>.open("r").read().split("\n")[0]
print("line1 = %r" % line1)

如果这仍然不是决定性的,(但前提是您可以使用管理 shell 重现问题,然后创建一个包含这些行的小文件。

from <your_application>.models import <YourModel>
entry = <YourModel>.objects.get(id=<idofentry>)
import pdb; pdb.set_trace()
line1 = entry.<filefieldname>.open("r").read().split("\n")[0]
print("line1 = %r" % line1)

并从管理外壳导入它。代码应该进入调试器,现在您可以单步执行打开的函数,看看您是否在某些猴子补丁中遇到了一些奇怪的函数。


推荐阅读