为什么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结尾。

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

一些奇怪的事情:

  • 它以前可以正常运行,但是在某个时候它已将其破坏(我尝试回滚到以前的提交,但它仍然很不稳定,因此可能依赖项已经更新,而我的{{1 }}。在我的测试中错过了它,因为它在应用程序中很少使用。

  • 如果我使用requirements.txt而不是readlines()读取相同的文件,则会看到包裹在readline()中的文件的正确字符串表示形式

  • 如果我使用解释器中的直接Python [b'...']open()来正常读取文件

  • 使用readline()强制文本模式不会更改行为,mode='rt'

  • 文件存储在Minio存储桶中,因此默认存储是mode='rb'中的storages.backends.s3boto3.S3Boto3Storage,而不是默认的Django存储类。这意味着django-storagesboto3botocore也在混合中,这使我的调试更加混乱。

抓狂地研究为什么这以前起作用以及我做错了什么。

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

编辑

让我指出,对此的解决方法只是使用

s3fs

但是我仍然想知道发生了什么事。

编辑2

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

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

这看起来很奇怪。 我认为您尝试执行以下操作后会立即看到解决方案(如果确实无法找到答案,我会更新我的答案或删除它,但我很有信心)

假设有一些代码,就是monkeypatching file.open或django视图功能。

我建议是:

使用manage.py runserver启动代码 广告以下代码进行管理(作为 第一行 )()

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()也在读文件stan的方式。 您是否只是使用cat filename从命令行打开文件(或者在Windows中使用type filename打开文件?

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

附录2:

好吧,如果您无法在manage.py runserver中进行尝试,那么如果尝试使用manage.py 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)

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

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)

并从管理外壳将其导入。 代码应该进入调试器,现在您可以单步执行open函数,并查看是否在某些monkeypatch中使用了sime weird函数。

本文链接:https://www.f2er.com/2909515.html

大家都在问