为什么Django FieldFIle readline()返回文本文件的十六进制版本?

2024-10-01 07:43:29 发布

您现在位置:Python中文网/ 问答频道 /正文

有奇怪的问题。你知道吗

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

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

文件是文本,utf-8编码,行以\r\n结尾。你知道吗

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

一些奇怪的事情:

  • 它以前工作正常,但在某个时候更新破坏了它(我尝试回滚到以前的提交,但它仍然不稳定,因此可能是依赖项已更新,而不是来自我的requirements.txt)。在我的测试中错过了它,因为它是应用程序中很少使用的部分。

  • 如果我用readlines()而不是readline()读取同一个文件,我会看到文件的正确字符串表示形式被[b'...']

  • 如果我从解释器中使用纯Python open()readline()执行此操作,文件将正常读取

  • mode='rt'强制文本模式不会改变行为,mode='rb'

  • 文件存储在Minio bucket中,因此defaut存储是来自django-storagesstorages.backends.s3boto3.S3Boto3Storage,而不是默认的Django存储类。这意味着boto3botocores3fs也在混合中,这使得调试更加混乱。

我一直在琢磨为什么这样做会奏效,我做错了什么。你知道吗

环境是在Docker容器中运行的Python3.8、Django2.2.8和3.0(结果相同)。你知道吗

编辑

我要指出的是,解决这个问题的方法就是

row = f.readline().decode()

但我还是想知道发生了什么。你知道吗

编辑2

除此之外,FieldFile.open文件()将文件作为二进制文件读取,而plain Python open()将文件作为文本文件读取。你知道吗


Tags: 文件django字符串文本应用程序编辑readlinemode
1条回答
网友
1楼 · 发布于 2024-10-01 07:43:29

这看起来很奇怪。 我想你会看到解决方案后,立即尝试以下(然后我会更新我的答案或删除它,如果它真的没有帮助找到它,但我很有信心)

假设有一些代码,那就是monkeypatching文件.open或者django视图函数。你知道吗

我的建议是:

开始你的代码管理.py运行服务器 广告跟随代码管理.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:

如果你不能在manage.py runserver中尝试,那么如果你尝试用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)

如果这仍然不是决定性的(但前提是您可以用managementshell重现问题),那么创建一个包含行的小文件。你知道吗

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)

并从管理shell导入它。 代码应该进入调试器,现在您可以单步执行open函数,看看是否在monkeypatch中使用sime-weird函数。你知道吗

相关问题 更多 >