Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么Django FieldFIle readline()返回文本文件的十六进制版本?_Python_Django_Boto_Readline - Fatal编程技术网

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

Python 为什么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” 一些奇怪的事情: 它以前工作

有一个奇怪的问题

我有一个Django应用程序,它打开一个文件(表示为Django
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存储是
    storages.backends.s3boto3.s3boto3存储
    from
    django storages
    ,而不是默认的django存储类。这意味着
    boto3
    botocore
    s3fs
    也在混合中,这使我在调试时更加困惑

让我挠头的是,为什么以前这样做有效,我做错了什么

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

编辑

让我指出,解决这个问题的方法就是使用

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
是指n
FieldFile
的实例,因此它可以同样容易地成为
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)