Djangoフレームワークでのファイルのアップロード
Djangoフレームワークを利用してファイルのアップロードをする方法について紹介しています。
例えばブログなどのWebサービスを実装する際に、ブログの投稿をファイルの形でサーバーに保存して表示する際などに利用できます。
ブログのWebサービス
この記事ではブログのWebサービスを想定した実装を考えます。実際にはもう少しシンプルにするので、「ブログのような」サービスです。 一つの方法は、原稿の中身がHTMLやMarkdownなどのようにテキスト形式のデータの場合には、ファイルの中身をデータベースにそのまま格納する方法も可能です。
もう一つの方法は、投稿の原稿をファイルの形でサーバー側に保存して、表示する際にファイルの中身を読み込んで表示する方法です。今回は、ファイルの形でサーバー側に保存する方法を紹介します。
この形式の場合、ファイルはWebホスティングしているサーバーのフォルダに保存される形になります。
この例では、シンプルにHTMLで書かれた投稿の原稿を表示するサービスを実装します。
* アップロードするファイルを選択
* 選択したファイルを表示
アップロードするファイルの選択
アップロードするファイルを選択するための仕組みを作ります。 アップロードするファイルはWebブラウザを使っているPCにある事を前提にしています。 PCからアップロードするファイルを選んで、サーバー上にアップデートするようにします。
ファイルの選択は、Webページにフォームを作ってファイルを選択するUIを作ります。その上で、ファイルをアップロードするボタンをクリックしたらファイルをサーバーに送るようにします。
この実装は静的なファイルを利用する場合と同様で、実際はWebホスティングを行うサーバーによって変わってきます。この記事ではまず、開発用のサーバーでその機能を実現する方法について紹介します。実際にWebサーバー上で公開する場合に関しては改めて別の記事で紹介します。
フォームの部分の記述の例です。
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label>File</label>
<input class="form-control" type="file" name="upload"/>
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</form>
ファイルを選択後に、「Submit」ボタンを押すと、WebホスティングしているサーバーにHTTPのPOSTメソッドを使って送るようになっています。
あとはサーバー側で処理をするようにします。
サーバー側の設定
サーバー側でやることは
* URLのマッピング(urls.py)
* ページの設定(views.py)
* テンプレートの設定
URLのマッピング
Djangoのアプリのフォルダにある、urls.pyを設定します。この例では、「/post」というURLが指定されたらフォームのページを表示するようにします。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name="index"),
path('post/', views.post, name="post"),
]
ページの設定
views.pyでは、「/post」のURLが選択された場合、サーバーに来るHTTPのリクエストタイプによって処理を分けています。 通常のリクエスト(HTTPのGET)の場合は、ファイルを選択するフォームを表示するようにします。
HTTPの「POST」のリクエストの場合、ファイル情報が含まれているので、ファイル情報を受け取って、一旦ファイルをサーバー側に保存します。
その後、保存したファイルから、必要な情報を取り出して、テンプレートに埋め込んで表示するようになっています。
import os
from django.conf import settings
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request, 'base.html')
def post(request):
if request.method == 'POST':
print("POST")
path = os.path.join(settings.MEDIA_ROOT, request.FILES['upload'].name)
with open(path, "wb") as output_file:
for chunk in request.FILES['upload'].chunks():
output_file.write(chunk)
f = open(path, "r")
contents = f.read()
context = {
"name": request.FILES['file_upload'].name,
"contents": contents
}
return render(request,"app/master.html", context )
else:
return render(request, "app/file_upload.html")
テンプレートは、アプリのフォルダに「templates/app」というフォルダを作成してその下に、「master.html」という名前で作成します。ページのタイトル名はファイル名を、選択されたファイルに書かれた、HTMLをボディのタグに埋め込んで表示します。
<!DOCTYPE html>
<html>
<head>
<title>{{ name }}</title>
</head>
<body>
{{ contents| safe }}
</body>
</html>
これで、HTMLで書かれたファイルの中身「contents」がこのテンプレートに埋め込まれて表示されます。
Djangoの設定
これは、開発環境のサーバーの設定になります。 実際に、Djangoで作成したアプリをインターネットで公開する場合(デプロイする場合)は、利用するホスティングするサーバーの設定によって変わってきます。詳細は別途記事を各予定ですのでこの記事では、本番の公開用の環境の話には触れません。
プロジェクトフォルダの「settings.py」に以下の設定を追加します。
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Djangoのプロジェクトの「manage.py」があるフォルダに「media」を作成します。
これで、ファイルはこの設定で、開発環境の場合はこのフォルダに保存されます。 先程した、「views.py」でその設定をしています。
save_path = os.path.join(settings.MEDIA_ROOT, request.FILES['file_upload'].name)
がその部分です。
この設定は?
この設定は、「settings.py」の「DEBUG」の設定が
DEBUG = True
の場合のみ有効です。
上にも書いていますが、実際にインターネットに公開(デプロイ)するためにはWebホスティングのサーバーによって必要な設定やモジュールが変わってきます。実際に、デプロイする際は、「settings.py」も開発時の設定とは違う設定も必要です。
この状態で、開発用のサーバーを起動して、 「127.0.0.1:8000/post」にアクセスすると、ファイル選択用のフォームが表示されて、HTMLの記述のフィアルを選択して「Submit」をクリックすると、ファイルのHTMLの部分が表示されます。
開発用のフォルダを見ると作成した、「media」フォルダの中に選択したファイルが保存されているのがわかります。
まとめ
今回は、開発用のサーバーのみの動作ですが、Djangoでファイルをアップロードする仕組みができました。同じ様な機能を使って、ブログを投稿して表示するようなWebサービスなども実現できるようになります。
開発用のサーバーで設定するのはやり方が同じなので、設定は簡単ですが実際のWebホストにデプロイする場合は、ホスティングサーバーによって設定が違ってくるので、設定方法は一つではありません。 そのため、この記事では公開用の設定には触れていません。
まずは、開発用のサーバーで一通りの実装の方法の取得を目指します。