Djangoでファイルをアップロードするのは多くの手順を踏む必要があり、なかな大変ですよね。
そこで、この記事ではファイルをアップロードする方法について分かりやすく解説していきます。
ファイルをアップロードする上でおさえるポイントをまとめました
ファイルをアップロードするためには、おさえるべきポイントが沢山あり、一言でそのやり方をお伝えするのは残念ながら難しいです。
ですので、まずはファイルをアップロードする上でおさえておくべきポイントについてみていきましょう。
そのポイントは以下の通りです。
- htmlフォームは、enctype="multipart/form-data"の指定をする必要がある
- ファイルを扱うには、FileFieldかImageFieldを使う
- MEDIA_URLとMEDIA_ROOTを設定する
- urlpatternsの設定をする
- ファイル自体はサーバーに保存されるだけで、データベースには保存されない
まずは、このポイントについて詳しく見ていきましょう。
htmlフォームは、enctype="multipart/form-data"の指定をする必要がある
これはDjangoではなくhtmlの範囲なのですが、意外と忘れてしまいがちなポイントです。
ファイルをアップロードするときには、<form method="POST' enctype="multipart/form-data">と、enctypeの指定をする必要があります。
デフォルトで何も入力しないと、enctype="application/x-www-form-urlencoded"となりますが、ファイルを添付する場合は複雑な処理が必要なので、multipart/form-dataを使わなければいけないと覚えるようにしましょう。
ファイルを扱うには、FileFieldかImageFieldを使う
これはそのままですね。モデルを使ってファイルを扱う場合は、FileFieldかImageFieldを使うようにしましょう。
FileFieldとImageFieldの違い
ここでFileFieldとImageFieldの違いについて簡単にお伝えします。
ImageFieldは、FileFieldが持つメソッドと属性を継承しています。
ただ、ImageFieldの場合は、アップロードされたファイルが画像かどうかを確認する機能と、幅と高さを指定できる属性がある点が、FileFieldと異なります。
MEDIA_URLとMEDIA_ROOTを設定する
次のポイントは、MEDIA_URLとMEDIA_ROOTを設定することです。
MEDIA_ROOTは、ファイルがアップロードされたときに、そのファイルが保存されるディレクトリ(フォルダ)を指定するものです。
例えば、MEDIA_ROOT = os.path.join(BASE_DIR, 'mediadir')とした場合、BASE_DIRと同じ階層にあるmediadirというディレクトリの中にファイルが保存されます。
BASE_DIRについて詳しく理解したい方は、BASE_DIRを分かりやすく解説【これで場所と構造がわかります】という記事を参考にしてみて下さい。
また、MEDIA_URLはurlと画像ファイルを紐づけるために指定されます。
といってもこれでは抽象的でイメージが湧きづらいですので、具体例でみていきましょう。
例えば、MEDIA_URL = '/mediaurl/'として、ファイル名が「a.png」だったとします。
この時、このファイルにアクセスするためのurlは、localhost:8000/mediaurl/a.pngとなります。
つまり、urlの絶対パスでファイルを参照するのではなく、urlpatternを使ってファイルを参照するという形になります。
(その設定は次のsettings.pyファイルの設定で行っていきます。)
urlpatternsの設定をする
上記のMEDIA_ROOTとMRDIA_URLとも関係してくるのですが、djangoではurlpatternsを使って画像ファイルとurlの対応付けをしていきます。
その対応付けの設定は以下の形で行います。
*ただし、これは開発中のみ適用するようにします。本番環境では、ApatchやNginxなどのウェブサーバーと画像の保存場所を関連付けます(サーバーをを効率的に動かすためです)。
コードif settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
イメージとしては、path('url', view)というコードにおいて、urlという文字列とviewを関連付けるような形です。
つまり、static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)というコードにおいて、MEDIa_urlという文字列とMEDIA_ROOT(すなわち、ファイルが入っている場所)をひもづけるようなイメージです。
ファイル自体はサーバーに保存されるだけで、データベースには保存されない。
最後のポイントは、ファイルがデータベースに保存されることはないということです。
データベースに保存されるのは、あくまでも画像にアクセスするためのurlだけです。
つまり、データベースの中のデータを消したとしても、ファイル自体はサーバーに残っていることに注意しましょう。
コードを書いていきましょう
上記のポイントをおさえながら、実際にコードを書いていきましょう。
コード-upload.html
1 <form method="post" enctype="multipart/form-data">
2 {% csrf_token %}
3 <input type="file" name="myfile">
4 <button type="submit">アップロードする</button>
5 </form>
6 {% if uploaded_file_url %}
7 <p>ファイルのアップロード場所は、 <a href="{{ uploade_url }}">{{ upload_url }}</a>です。</p>
8 {% endif %}
このファイルの内容はほとんどがhtmlの範囲ですので、下のdjangoのタグの部分を中心に説明をしていきます。
コードの解説(1) 6行目で{% if upload_url %}と書かれていますが、これはupload_urlがTruの場合にifの下のコードを実行するという意味です。
upload_urlは次のviews.pyファイルで定義していますが、「アップロードするファイルが存在していること」がif文実行の条件です。
アップロードするファイルが存在する場合は、そのurlが表示されるようにしています。
次にviewを作っていきましょう。
コード-views.py
1 from django.shortcuts import render
2 from django.core.files.storage import FileSystemStorage
3 def fileupload(request):
4 if request.method == 'POST' and request.FILES['htmlfile']:
5 htmlfile = request.FILES['htmlfile']
6 fileobject = FileSystemStorage()
7 filedata = fileobject.save(htmlfile.name, htmlfile )
8 upload_url = fileobject.url(data)
9 return render(request, 'upload.html')
10 return render(request, 'upload.html')
コードの解説(1) 4行目のrequest.FILESは、ファイルがフォームを通じて送られた場合に作成される「ファイルに関する情報」です。
ここでは、formのname属性で指定したデータが、request.FILESに存在することをif文実行の条件としています。
(2) フォームで送信されたフォームのデータを、htmlfileという変数に入れています。
(3) FileSystemStorageクラスからオブジェクトを作ります。
FileSystemStorageクラスは、モデルクラスの画像版のようなイメージを持つと良いでしょう。
(4) fileobject.save()というメソッドでファイルに関するデータを保存します。そして、保存したデータをfiledataという変数に入れます。
ファイルをサーバーに保存するために必要なコードはここまでです。
(5) アップロードしたファイルのurlをupload_urlという変数に入れます。このデータは、htmlファイルにおいて、アップロードが完了したときにそのurlを表示させるために使います。
実際にアップロードしてみる
ここまで書いたコードをベースに、実際にファイルをアップロードしてみましょう。
まずは、左上の「ファイルを選択」をクリックして、ファイル(画像)を選択します。
今回は、以下のパソコンの画像を選択したとしましょう。
その上で、「アップロードする」のボタンを押します。ボタンを押した後の画面がこちらです。
アップロードされた場所もしっかりと指定されていることが分かります。
次に、ファイルがしっかりとアップロードされているか確認してみましょう。
コードエディタを使って、フォルダの中身を確認していきます。
左上に、画像がしっかりと保存されていることが分かります。MEDIA_ROOTで指定した「media-directory」に画像が保存されていることも確認しましょう。
このように、画像がしっかりと保存されていることが確認できました。
ModelFormを使ったの場合
次に、ModelFormを使って実装する場合についてみていきましょう。
まずはmodels.pyファイルでモデルを作っていきます。
コードmodels.py
1 class FileModel(models.Model):
2 title = models.CharField(max_length=100)
3 uploadplace = models.FileField(upload_to='upload/')
コードの解説ここでのポイントは、3行目です。
ここではFileFieldを定義していますが、FileFieldではupload_toという引数を指定しなければエラーになるという点に注意しましょう。
そして、ここで指定したupload_toは、MEDIA_ROOTの下のディレクトリして扱われます。
例えば、MEDIA_ROOTが'/media/'でupload_toが'upload/'の場合、アップロードしたファイルはlocalhost:8000/media/uploadというディレクトリの中に保存されるという点をおさえておきましょう。
次に、upload.htmlファイルの編集を進めていきましょう。
コードfrom django import forms
from .models import Document
class UploadForm(forms.ModelForm):
class Meta:
model = FileModel
fields = ('title', 'uploadplace', )
ここは普通のModelFormを定義しているだけですね。
次に、views.pyファイルを作っていきましょう。
コード1 def form_upload(request):
2 if request.method == 'POST':
3 form = UploadForm(request.POST, request.FILES)
4 if form.is_valid():
5 form.save()
6 return redirect('list')
7 else:
8 form = UploadForm()
9 return render(request, 'mfupload.html', {
'form': form
})
コードの解説(1) 基本的にはモデルクラスでオブジェクトを作る場合と同じです。
一点、3行目でformオブジェクトを作っていますが、ここでは引数としてrequest.POSTだけではなく、request.FILESも指定する必要があるという点に注意しましょう。
最後にhtmlファイルを作って完成です。
コード<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">アップロードする</button>
</form>
これも普通のフォームですので、アップロード関連で新しい部分はないでしょう。
ファイルのアップロードをするには、MEDIA_ROOTなど、覚えることが多いですが、基本的にやっていることはオブジェクトを作ってそのオブジェクトを保存しているだけです。
この基本をしっかりとおさえておけば、ファイルのアップロードも自由にできるようになるでしょう。