2012-01-05 33 views
2

我有以下用於通過django管理文件下載的代碼。由django提供服務時獲取一個空文件

def serve_file(request, id): 

    file = models.X.objects.get(id=id).file #FileField 
    file.open('rb') 
    wrapper = FileWrapper(file) 
    mt = mimetypes.guess_type(file.name)[0] 
    response = HttpResponse(wrapper, content_type=mt) 

    import unicodedata, os.path 
    filename = unicodedata.normalize('NFKD', os.path.basename(file.name)).encode("utf8",'ignore') 
    filename = filename.replace(' ', '-') #Avoid browser to ignore any char after the space 

    response['Content-Length'] = file.size 
    response['Content-Disposition'] = 'attachment; filename={0}'.format(filename) 

    #print response 
    return response 

不幸的是,我的瀏覽器在下載時會得到一個空文件。

打印的響應似乎是正確的:

Content-Length: 3906 
Content-Type: text/plain 
Content-Disposition: attachment; filename=toto.txt 

blah blah .... 

我有類似的代碼運行正常。我看不出有什麼問題。任何想法?

PS:我已經測試提出的解決方案here並獲得相同的行爲

更新: 更換wrapper = FileWrapper(file)通過wrapper = file.read()似乎解決問題

更新:如果我評論了print response,我得到類似的問題:。該文件是空的。唯一的區別是:FF檢測到一個20字節的大小。 (該文件大於此)

回答

1

文件對象是一個可重寫的,並且是一個生成器。它在被苛求之前只能被讀取一次。然後,您必須重新制作一個新的對象,使用一種方法從對象開始再次開始(例如:seek())。

read()返回一個字符串,可以多次讀取而沒有任何問題,這就是爲什麼它可以解決您的問題。

所以,只要確保如果你使用像對象一樣的文件,你不會連續讀兩次。 E.G:不要打印,然後返回。

+0

好點!然而,我已經評論了印刷品並且仍然具有類似的行爲(事實上,我已經添加了印刷品以嘗試瞭解印刷品)。看到我的更新 – luc 2012-01-05 11:46:28

+0

是的,但是什麼證明你的回答只是迭代一次?畢竟,響應使用你的文件包裝來完成它的內容。 – 2012-01-05 15:54:07

0

django documentation

FieldFile.open(模式= 'RB')的行爲類似於標準Python打開() 方法,並打開與此實例中由模式指定的模式 相關聯的文件。

如果它像蟒蛇open,那麼它應該返回一個文件對象,應該這樣使用:

f = file.open('rb') 
wrapper = FileWrapper(f) 
+0

它似乎file.open不會返回任何內容,但修改文件實例 – luc 2012-01-05 12:59:46