python - 为什么 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”。
一些奇怪的事情:
它以前可以正常工作,但在某些时候更新已经破坏了它(我尝试回滚到以前的提交,但它仍然很不稳定,所以可能是一个依赖项已经更新,而不是来自 my 的东西
requirements.txt
)。在我的测试中错过了它,因为它在应用程序中很少使用的部分。readlines()
如果我使用而不是读取相同的文件,readline()
我会看到包含在[b'...']
如果我使用直接 Python
open()
并readline()
从解释器执行该文件,则该文件可以正常读取强制文本模式
mode='rt'
不会改变行为,也不会mode='rb'
该文件存储在 Minio 存储桶中,因此默认存储
storages.backends.s3boto3.S3Boto3Storage
来自django-storages
而不是默认的 Django 存储类。这意味着boto3
,botocore
和s3fs
也在混合中,使我在调试时更加困惑。
对为什么这之前有效以及我做错了什么而摸不着头脑。
环境是在 Docker 容器中运行的 Python 3.8、Django 2.2.8 和 3.0(结果相同)。
编辑
让我指出,解决这个问题只是使用
row = f.readline().decode()
但我仍然想弄清楚发生了什么。
编辑 2
除此之外, FieldFile.open() 将文件作为二进制文件读取,而普通 Python open() 将文件作为文本文件读取。
解决方案
这似乎很奇怪。我想你会在尝试关注后立即看到解决方案(如果它真的无助于找到它,我会更新我的答案或删除它,但我很有信心)
假设有一些代码,即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)
并从管理外壳导入它。代码应该进入调试器,现在您可以单步执行打开的函数,看看您是否在某些猴子补丁中遇到了一些奇怪的函数。
推荐阅读
- twitter-bootstrap - Xpages 与 OneUI 和 Domino HCL 11 的兼容性问题
- c++ - Magick++ ``depth`` 的行为与 ``convert -depth`` 不同
- python - 为什么在 Python 中 filter(sorted(xs)) 比 sorted(filter(xs)) 快?
- java - Netbeans Java 中的预览设计不同于运行时设计
- pandas - 熊猫计数器作为新列
- python-3.x - ValueError:在 pytube 中解压的值太多(预期为 2)
- c++ - C++ 异常调用 _exit
- javascript - 如何使用 fetch 在前端存储和处理 JWT 令牌,以及如何存储它?
- amazon-web-services - AWS API Gateway 限制未按预期工作
- python - PyInstaller and Kivy builds but doesn't run