Python

【Python】Djangoでファイルのアップロード

  • このエントリーをはてなブックマークに追加

Djangoでフォームからファイルを選択してアップロードする方法について説明します。

  • フォームのテンプレート
  • フォームから受信したときの処理

下準備

新しくファイルアップロードのアプリを作成します。

アプリ作成

アプリを作成します。

python manage.py startapp file_upload

設定

[プロジェクト名]/[プロジェクト名]/settings.pyにアプリを登録

INSTALLED_APPS = [
    'django.contrib.admin',
        ...
    'file_upload',
]

パスの登録

[プロジェクト名]/[プロジェクト名]/urls.py

from file_upload import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('file_upload',views.upload),
]

フォームクラスの作成

[プロジェクト名]/file_upload/templates/upload.html

from django import forms
class UploadFileForm(forms.Form):
    file = forms.FileField()

フォームテンプレートの作成

[プロジェクト名]/file_upload/forms.py

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>ファイルアップロード</title>
  </head>
  <body>
    <h1>ファイルをアップロード</h1>
    <form method="POST" enctype="multipart/form-data">{% csrf_token %}
      {{ form.as_p }}
      <button type="submit">アップロード</button>
    </form>
  </body>
</html>

viewsの作成

[プロジェクト名]/file_upload/views.py

from django.http import HttpResponse
from django.shortcuts import render
from .forms import UploadFileForm
import os
def upload(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        file_obj = request.FILES['file']
        if form.is_valid():
            file_name = file_obj.name# セキュリティ上は良くない
            if not os.path.exists(file_name):
                with open(file_name, 'wb+') as output:
                    for chunk in file_obj.chunks():
                        output.write(chunk)
                return HttpResponse('Success!')
            else:
                return HttpResponse('file already uploaded')
        else:
            return HttpResponse('invalid form')
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

アプリを起動して、
http://localhost:8000/file_upload
へアクセスしましょう。すると、フォームが表示されます。
ファイルを選択してアップロードをクリックすると、
プロジェクト配下にファイルが保存されるようになります。

セキュリティ上のリスクについては十分注意!

しかし、ファイル名を利用者が任意に決められるのはセキュリティ上リスクが高いです。
たとえば、../../hoge.jpgのようなファイル名を指定された場合、
プロジェクト外のファイルを書き換えられる可能性があります。
そのため、ファイル名は基本的にこちらで決めるような仕様にするのが望ましいです。
また、どうしてもファイル名を使用したい場合、os.path.basenameをつかって、
ファイル名だけを抜き出すなどの工夫を行う必要があります。
さらに、アプリの実行ユーザーへ適切なアクセス権を設定する必要もあります。
必要以上にファイルアクセスを許さないことも重要です。

  • このエントリーをはてなブックマークに追加