Python 为什么Django FieldFIle readline()返回文本文件的十六进制版本?
有一个奇怪的问题 我有一个Django应用程序,它打开一个文件(表示为DjangoPython 为什么Django FieldFIle readline()返回文本文件的十六进制版本?,python,django,boto,readline,Python,Django,Boto,Readline,有一个奇怪的问题 我有一个Django应用程序,它打开一个文件(表示为DjangoFieldFile),并使用readline()读取每一行,如下所示: with file.open(mode='r') as f: row = f.readline() # do something with row... 文件为文本,utf-8编码,行以\r\n结尾 问题是每一行都被读取为字符串的十六进制表示形式,因此我得到的不是“Hello”,而是“48656c6f” 一些奇怪的事情: 它以前工作
FieldFile
),并使用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存储是
fromstorages.backends.s3boto3.s3boto3存储
,而不是默认的django存储类。这意味着django storages
、boto3
和botocore
也在混合中,这使我在调试时更加困惑s3fs
row = f.readline().decode()
但我还是想弄清楚到底发生了什么
编辑2
除此之外,FieldFile.open()将文件作为二进制文件读取,而plain Python open()将文件作为文本文件读取。这似乎很奇怪。
我想你会在尝试以下内容后立即看到解决方案(然后我会更新我的答案或删除它,如果它确实无助于找到它,但我很有信心)
假设有一些代码,即monkeypatching file.open或django view函数
我的建议是:
使用manage.py runserver启动代码
下面是manage.py的Ad代码(作为第一行)
然后将代码直接添加到文件上方一行的视图中。打开
print("ID of file.open before opening is", id(file.open)
如果两个ID都不一样,那么您的open函数就有问题了。
如果两者都是相同的,那么问题一定在其他地方
如果你看不到这两张照片的输出,可能是有什么东西把你的视图弄乱了
如果这不起作用,那么尝试使用
open()
而不是file.open()
您使用file.open()
附录1:
所以你说的是,这个文件是一个类的对象实例,它是一个文件字段吗?
在任何情况下,您都可以获取文件名,并使用普通的open()
打开它,以查看它是否只是file.open()
做有趣的事情,或者它是否也是open()
以这种方式读取的。
您是否刚刚用cat filename
从命令行打开文件(或者如果在windows下用键入filename
如果这不起作用,我们可以添加跟踪,跟踪正在执行的每一行源代码
附录2:
如果您不能在manage.py运行服务器中尝试此操作,那么如果您尝试使用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)
from.models导入
entry=.objects.get(id=)
line1=entry..open(“r”).read().split(“\n”)[0]
打印(“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)
from.models导入
entry=.objects.get(id=)
导入pdb;pdb.set_trace()
line1=entry..open(“r”).read().split(“\n”)[0]
打印(“line1=%r”%line1)
并将其从命令行管理程序中导入。
代码应该进入调试器,现在您可以单步执行open函数,查看是否在某个monkeypatch中使用sime-weird函数。我怀疑您是正确的,并且在存储管理器链的某个地方它是monkeypatch。现在尝试一下。请澄清,file
是指nFieldFile
的实例,因此它可以同样容易地成为x.open()
因此,进一步检查后,我认为这是正确的方向,但诊断方法是错误的。该应用程序由uWSGI在生产和开发环境中运行-我们不使用runserver
,因为它无法设置必要的环境和依赖项。另外file.open()
是open()'在对象上调用方法
文件'-不确定id是否保持不变,并且在任何情况下,文件
在应用程序实例化时都不存在。进一步增强了答案是的,这很奇怪。因此,我的答案不是很有帮助,我也没什么想法了。正如你提到的,你的文件对象不是真正的文件对象,但有一些le-like对象(boto3…)所以我认为要找到根本原因并不那么容易,除非你设法创建一个最小的可能的设置,它仍然可以复制行为,并且你可以显示,要删除/更改什么(例如boto3)以不再具有该行为。只是如果你有解决方案,不确定这是否值得
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)