為什么Django FieldFIle Readline()返回十六進制版本的文本文件? [英] Why is Django FieldFIle readline() returning the hex version of a text file?

查看:0
本文介紹了為什么Django FieldFIle Readline()返回十六進制版本的文本文件?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

有奇怪的問題。

我有一個Django應用程序,它打開一個文件(表示為DjangoFieldFile),并使用readline()讀取每一行,如下所示:

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

該文件為文本,采用UTF-8編碼,行以 結尾。

問題是每一行都被讀取為字符串的十六進制表示形式,因此我得到的不是"Hello",而是"48656c6c6f"。

一些奇怪的事情:

  • 它以前工作正常,但在某個時候被更新破壞了(我嘗試回滾到以前的提交,但它仍然不穩定,所以可能是依賴項已經更新,而不是我的requirements.txt中的內容)。在我的測試中遺漏了它,因為它位于應用程序中很少使用的部分。

  • 如果我使用readlines()而不是readline()讀取相同的文件,我會看到[b'...']

  • 中包含的文件的正確字符串表示形式
  • 如果我直接使用Pythonopen()readline()從解釋器讀取文件,則文件可以正常讀取

  • 使用mode='rt'強制文本模式不會改變行為,mode='rb'

  • 文件存儲在mini存儲桶中,因此默認存儲是storages.backends.s3boto3.S3Boto3Storagefromdjango-storages,而不是默認的Django存儲類。這意味著boto3、botocores3fs也混合在一起,這給我的調試帶來了更大的困惑。

抓撓我的頭,不知道為什么以前這樣做有效,我做錯了什么。

環境是在Docker容器中運行的Python3.8、Django 2.2.8和3.0(結果相同)。

編輯

讓我指出,解決此問題的方法只需使用

row = f.readline().decode()

但我還是想弄清楚發生了什么事。

編輯%2

此外,FieldFile.open()將文件讀取為二進制文件,而普通的Python Open()將文件讀取為文本文件。

推薦答案

這似乎非常奇怪。 我想你在嘗試下面的答案后會立即看到解決方案(如果確實無濟于事,我會更新我的答案或刪除它,但我很有信心)

假設有一些代碼,即monkeypatting file.open或Django視圖函數。

我的建議是:

從made.py runserver開始您的代碼 將以下代碼添加到made.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從命令行打開文件(還是使用type filename在Windows下打開文件?

如果這不起作用,我們可以在正在執行的源代碼的每一行后面添加跟蹤。

附錄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("
")[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("
")[0]
print("line1 = %r" % line1)

并從命令行管理程序導入它。 代碼應該進入調試器,現在您可以單步通過打開函數,并查看您是否在某個monkeypatch中使用了類似的奇怪函數。

這篇關于為什么Django FieldFIle Readline()返回十六進制版本的文本文件?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持IT屋!

查看全文
登錄 關閉
掃碼關注1秒登錄
發送“驗證碼”獲取 | 15天全站免登陸
全免费A级毛片免费看无码播放