DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

Djangoの使い方⑮モデルを使わずに、動的にファイルをアップロード、ダウンロードする

Djangoではファイルのアップロード&ダウンロード機能が備わっていますが基本的には静的なものです。

たとえばユーザーによって保管場所を変えたりディレクトリを作成したり、アクセスされるタイミングによってダウンロードファイルを変えたりと動的にファイルの制御をしたいことがあるものです。

 

アップロード

HTML(必要な部分だけ)

<form id="upload" method="post" action="" enctype="multipart/form-data">

    {% csrf_token %}

        <input type="file" name="upload">

        <button type="submit">送信する</button>

</form>

これだけ。 csrf_tokenは地味に忘れがちなので要注意。

f:id:DreamerDream:20220120121848p:plain

このformタグに enctype="multipart/form-data" が書かれていないとアップロードデータがNoneになってしまいますので超注意です。

 

 

pythonコード(必要な部分だけ)

def upload( request ):

     #POSTリクエストのみ

    if request.method == 'POST':

        file = request.FILES.get('upload')

        #ファイルが無い場合は処理しない

        if file is not None:

            #アップロードされた元のファイル名

            name = file.name

            #ファイルタイプ

            type = file.content_type

            #データのサイズ(単位はbyte)

            size = file.size 

            #read() は一気に読み込むのでファイルが大きい場合はメモリリソースを食うので非推奨

            #data = file.read()

            if size < 1000000: #1MB以下のみ処理する

                #実際に保存するディレクトリとファイル名

                filename = '/dev/shm/testupload'

                full_filename = os.path.join("media", "files", filename )

                #書き込む

                fout = open( full_filename, "wb+")

                #chunks()でデータを分割しながら保存

                for chunk in file.chunks():

                    fout.write( chunk )

                fout.close()

こうするとアップロードされたファイルは任意の場所に任意のファイル名で(例の場合は /dev/shm/testupload )保存されます。

 

 

ダウンロード

HTML記述は無し。アクセスされたら即ダウンロード開始。

 

python(必要な部分のみ)

viewファイルで

from django.http import FileResponse

 

filename = 'ダウンロードファイル名.txt'

filepath = '/dev/shm/testupload'

return FileResponse(  open(filepath, "rb") , as_attachment=True, filename=filename)

 

これだけ。

FileResponseをインポートすることと、as_attachmentがTrueだと即ダウンロード、Falseだとブラウザで開くという動きになるようです。

 

ダウンロードされるfilenameを任意で変更できるのは面白いですね。

例えば /download/photo にアクセスされると、「今日のおすすめの写真.jpg」ファイルがダウンロードされる。

f:id:DreamerDream:20220120123114j:plain

というような使い方ができるわけですね^^。

 

<参考>

https://living-sun.com/ja/python/718042-django-simplest-way-to-save-file-to-folder-on-disk-without-using-a-model-python-django-file-upload-upload.html

 

前の記事

dreamerdream.hateblo.jp

 

kampa.me