Django 實現下載檔案功能
基於Django建立的網站,如果提供檔案下載功能,最簡單的方式莫過於將靜態檔案交給Nginx等處理,但有些時候,由於網站本身邏輯,需要透過Django提供下載功能,如頁面資料匯出功能(下載動態生成的檔案)、先檢查使用者許可權再下載檔案等。因此,有必要研究一下檔案下載功能在Django中的實現。
最簡單的檔案下載功能的實現
將檔案流放入HttpResponse物件即可,如:
def file_download(request):
# do something...
with open('file_name.txt') as f:
c = f.read()
return HttpResponse(c)
這種方式簡單粗暴,適合小檔案的下載,但如果這個檔案非常大,這種方式會佔用大量的記憶體,甚至導致伺服器崩潰。
更合理的檔案下載功能
Django的HttpResponse
物件允許將迭代器作為傳入引數,將上面程式碼中的傳入引數c
換成一個迭代器,便可以將上述下載功能最佳化為對大小檔案均適合;而Django更進一步,推薦使用 StreamingHttpResponse
物件取代HttpResponse
物件,StreamingHttpResponse
物件用於將檔案流傳送給瀏覽器,與HttpResponse物件非常相似,對於檔案下載功能,使用StreamingHttpResponse
物件更合理。
因此,更加合理的檔案下載功能,應該先寫一個迭代器,用於處理檔案,然後將這個迭代器作為引數傳遞給StreaminghttpResponse
物件,如:
from django.http import StreamingHttpResponse
def big_file_download(request):
# do something...
def file_iterator(file_name, chunk_size=512):
with open(file_name) as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
the_file_name = "file_name.txt"
response = StreamingHttpResponse(file_iterator(the_file_name))
return response
檔案下載功能再次最佳化
上述的程式碼,已經完成了將伺服器上的檔案,透過檔案流傳輸到瀏覽器,但檔案流通常會以亂碼形式顯示到瀏覽器中,而非下載到硬碟上,因此,還要在做點最佳化,讓檔案流寫入硬碟。最佳化很簡單,給StreamingHttpResponse物件的Content-Type
和Content-Disposition
欄位賦下面的值即可,如:
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="test.pdf"'
完整程式碼如下:
from django.http import StreamingHttpResponse
def big_file_download(request):
# do something...
def file_iterator(file_name, chunk_size=512):
with open(file_name) as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
the_file_name = "big_file.pdf"
response = StreamingHttpResponse(file_iterator(the_file_name))
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name)
return response
注:轉載本文,請與Gevin聯絡
歡迎關注我的微信公眾賬號