django-3つの方法でファイルのダウンロードを実現
5290 ワード
実際のプロジェクトでは、excel、pdf、ファイルのダウンロードなどのダウンロード機能が必要になることが多い.もちろん、Webサービスを使用してnginxなどのダウンロードに使用できるリソースサーバを自分で構築することができます.ここでは、djangoのファイルのダウンロードについて説明します.
ここでダウンロードしたファイルをプロジェクトmediaディレクトリに保存します.もちろん実際にはそうはいきません.
方法一:HttpResponseを使用する
HttpResponseには大きな弊害があり、ファイルを読み取り、メモリをロードしてから出力するのが原理です.ダウンロードファイルが大きい場合、このメソッドは多くのメモリを消費します.大きなファイルをダウンロードする場合、DjangoはStreamingHttpResponseとFileResponseの方法をお勧めします.この2つの方法は、サーバメモリにロードしないで、ダウンロードファイルのバッチ(Chunks)をユーザーのローカルディスクに書き込みます.
方法2:StreamingHttpResponseの使用
方式3:FileResponseの使用
ファイル名の中国語の文字化けしの問題
ここでは英語のファイル名を使用し、ブラウザは正常に表示されますが、中国語を使用すると、
ファイルのプライベート化の2つの方法
ログインしたユーザーだけがファイルを表示およびダウンロードできるようにするには、2つの方法があります.ここでは、アイデアのみを提供します.アップロードファイルはmediaフォルダに置かれ、ファイル名は長いランダム文字列ネーミング(uuid)を使用しており、ユーザーがファイル名に基づいて何のファイルなのか推測できない.ビューとテンプレートにユーザーがログインしているかどうかを確認し、ログインまたは権限検証によって特定のurlを表示します.-シンプルで実現しやすく、セキュリティは高くありませんが、一般的なプロジェクトでは十分です. アップロードファイルは非メディアフォルダに置かれており、Djangoはメディアフォルダ内の各ファイルに独立したurlリソースを作成するだけであるため、ユーザーは具体的なファイルアドレスを知っていてもアクセスできません.ビューとテンプレートで、ユーザーがログインしているかどうかを確認したり、ログインしたり、権限検証後に自分で作成したダウンロード方法でファイルをダウンロードしたりします.-セキュリティは高いが、実装は比較的複雑である.
個人ダウンロードドキュメントviewビューコード
ここでダウンロードしたファイルをプロジェクトmediaディレクトリに保存します.もちろん実際にはそうはいきません.
方法一:HttpResponseを使用する
import os
from django.http import HttpResponse, Http404
def media_file_download(request, file_path):
with open(file_path, 'rb') as f:
try:
response = HttpResponse(f)
response['content_type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)
return response
except Exception:
raise Http404
HttpResponseには大きな弊害があり、ファイルを読み取り、メモリをロードしてから出力するのが原理です.ダウンロードファイルが大きい場合、このメソッドは多くのメモリを消費します.大きなファイルをダウンロードする場合、DjangoはStreamingHttpResponseとFileResponseの方法をお勧めします.この2つの方法は、サーバメモリにロードしないで、ダウンロードファイルのバッチ(Chunks)をユーザーのローカルディスクに書き込みます.
方法2:StreamingHttpResponseの使用
import os
from django.http import HttpResponse, Http404, StreamingHttpResponse
def stream_http_download(request, file_path):
try:
response = StreamingHttpResponse(open(file_path, 'rb'))
response['content_type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)
return response
except Exception:
raise Http404
方式3:FileResponseの使用
import os
from django.http import HttpResponse, Http404, FileResponse
def file_response_download1(request, file_path):
try:
response = FileResponse(open(file_path, 'rb'))
response['content_type'] = "application/octet-stream"
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)
return response
except Exception:
raise Http404
ファイル名の中国語の文字化けしの問題
ここでは英語のファイル名を使用し、ブラウザは正常に表示されますが、中国語を使用すると、
.xls
などのデフォルトのファイル名、またはutf-8符号化を使用した場合は、文字化けしています.解決策は次のとおりです.response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path(name))
ファイルのプライベート化の2つの方法
ログインしたユーザーだけがファイルを表示およびダウンロードできるようにするには、2つの方法があります.ここでは、アイデアのみを提供します.
個人ダウンロードドキュメントviewビューコード
from django.views import View
from django.conf import settings
from django.http import FileResponse,Http404
from django.utils.encoding import escape_uri_path
from .models import Doc
import requests
import logging
logger = logging.getLogger('django')
class Download(View):
"""
doc id,
"""
def get(self,request,doc_id):
doc = Doc.objects.only('file_url').filter(is_delete=False,id = doc_id).first()
if doc:
doc_url = doc.file_url
doc_url = settings.ITEM_DOMAIN_PORT + doc_url
try:
res = FileResponse(requests.get(doc_url,stream = True))
except Exception as e:
logger.info(' :{}'.format(e))
raise Http404(' ')
file_end = doc_url.split('.')[-1]
if not file_end:
raise Http404(' ')
else:
file_end = file_end.lower()
if file_end == "pdf":
res["Content-type"] = "application/pdf"
elif file_end == "zip":
res["Content-type"] = "application/zip"
elif file_end == "doc":
res["Content-type"] = "application/msword"
elif file_end == "xls":
res["Content-type"] = "application/vnd.ms-excel"
elif file_end == "docx":
res["Content-type"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
elif file_end == "ppt":
res["Content-type"] = "application/vnd.ms-powerpoint"
elif file_end == "pptx":
res["Content-type"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
else:
raise Http404(" !")
doc_filename = escape_uri_path(doc_url.split('/')[-1])
# http1.1
# inline,
# attachment
res["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(doc_filename)
return res
else:
raise Http404(" !")