Djangoにはデフォルトで画像などのメディアファイルをアップロードする仕組みが搭載されていますが、アップロード先にはURLさえ分かれば誰でもアクセスできるような状態となってしまいます。
そのため、ユーザ認証した人だけに画像などのメディアファイルを見れるようにしたい場合は、別段の対応が必要となります。
いろいろやり方はあるようですが、画像表示用の専用アプリを作ることで対応できたので、備忘録としてこの記事をまとめました。
目次
ユーザ認証した人だけメディアファイルを表示させるには?
ネットで調べてみると、Nginxの機能を使った方法やBASIC認証を使った方法、DjangoのアプリでContent-type: image/****のHTTPレスポンスで返す方法など、、、やり方はいろいろありそうです。
- DjangoでNginxのX-Accel-Redirectを使って、保護されたコンテンツを配信する方法
- 会員サイトで画像ファイルにもアクセス制限をかける方法
- 【Django】画像をアップロードして表示する
画像ファイルはNginxなどのリバースプロキシから返すのが主流のため、上の記事の中では「X-Accel-Redirect」を使う方法が良さそうですが、、、
私自身、Nginxに詳しくないことと、Djangoの勉強目的でWebアプリを作ろうとしていたこともあって、今回はAPLサーバ上で動作する画像表示用の専用アプリから画像を返す方法を採用することにしました。
動作イメージとしては以下です。
- ③と④の通信はユーザ認証搭載のWebアプリを介して行われるため、ユーザ認証した人のみ画像ファイルにアクセスできるようになります。
- 画像ファイルの格納先は外部には公開していないため、WebサーバやApplicationサーバから直接アクセスすることはできません。
ユーザ認証した人だけ画像を表示するアプリを作成する
ここでは、上の図でいうところの「ユーザ認証機能搭載Webアプリ」の部分を作る方法をまとめます。
ただし、構築する環境としては、runserverコマンドでできあがるサーバ環境を想定します。
なお、私の環境とディレクトリ構成は以下です。
- Python: 3.8
- Django: 3.0.4
mysite
│ manage.py
│
├─config (<= 設定ディレクトリ)
│ │ urls.py
│ └─ settings.py
│
├─apl (<= 画像を表示するためのアプリ)
│ │ urls.py
│ └─ views.py
|
└─mymedia (<= 画像ファイルを格納するディレクトリ)
| sample.jpg
※細かいファイルは省略しています。
手順1 ライブラリのインストール
Pythonで画像を扱うために、「Pillow」というライブラリを使用しますので、事前にインストールをします。
以下のコマンドでインストールできます。
$ pip install Pillow
手順2 設定ファイルに画像を格納するディレクトリを設定する
設定ファイル(settings.py)に画像を格納するディレクトリを設定します。
【mysite/config/settings.py】
MEDIA_ROOT = os.path.join(BASE_DIR, 'mymedia/')
MEDIA_ROOT
は、Djangoでメディアファイルをアップロードするときに指定するパラメータです。- 今回の記事では、アップロード機能は説明しませんが、上記のように設定することでアップロードしたファイルを「画像を表示するためのアプリ」で表示することができるようになります。
手順3 画像を表示するためのアプリを作成する
画像を表示するために以下のような「view.py」を作成します。
※アプリをまだ作成していなかった場合、「python manage.py startapp [アプリ名]」でアプリを作成してください。
【mysite/apl/views.py】
from django.views.generic import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django.conf import settings
from PIL import Image
from django.http import HttpResponse
import io
class MediaView(LoginRequiredMixin,View):
""" 画像取得 のビュー """
def get(self, request, filename, *args, **kwargs):
img = Image.open(settings.MEDIA_ROOT+filename)
imgByteArr = io.BytesIO()
img.save(imgByteArr, format=img.format)
imgByteArr = imgByteArr.getvalue()
response = HttpResponse(imgByteArr,status=200)
response["Content-Type"] = "image/jpeg"
response["Content-Disposition"] = "inline; filename={0}".format(filename)
return response
MediaView
はLoginRequiredMixin
を継承することで、ユーザ認証が必須のビューとしています。MEDIA_ROOT
にあるファイルをImage.open()
で読み取り、それをバイナリデータ化しimgByteArr
に格納しています。HttpResponse
には、正常を表すステータス200を設定し、コンテンツタイプを画像だと伝えています。response["Content-Disposition"] = "inline; filename={0}".format(filename)
を設定しないとブラウザがファイルダウンロードと間違えてしまうので、設定をしています。
手順4 URLconfに画像を表示するためのアプリを設定する
DjangoのURLディスパッチャでアクセスされたURLとビュー関数を紐づけてもらえるようにURLconfに設定をします。
【mysite/config/urls.py】
urlpatterns = [
path('', include('apl.urls')), # 追加
]
【mysite/apl/urls.py】
from django.urls import path
from . import views
app_name = 'apl'
urlpatterns = [
path('media/<str:filename>/', views.MediaView.as_view(), name='media'),
]
- 「自分のURL/media/画像ファイル名」にアクセスすると、指定した画像ファイルを取得できます。
画像が見れるか確認してみる
インターネット上にある画像を表示するのと同じように、imgタグを使って画像を表示できるようになっているはずです。
Djangoのテンプレート上で「mysite/mymedia/sample.jpg」を表示するには、以下のようにリンクを張ればみれるはずです。
【任意のテンプレート】
<img src="{% url 'apl:media' 'sample.jpg' %}" alt="">
補足 画像をアップロードする方法について
この記事では、画像ファイルを格納するディレクトリ「mysite/mymedia/」に画像ファイルが保存されている前提で記事を記載しましたが、画像ファイルをアップロードするディレクトリと「mysite/mymedia/」ディレクトリを同じにすることで、アップロードファイルを表示することができます。
画像をアップロードする方法については以下の記事が分かりやすかったです。
参考にリンクを載せておきます。
関連情報
Djangoのユーザ認証機能の実装方法を以下にまとめました。よろしければ、ご覧になってください。
自分は、DjangoをConoHa VPS上のDockerコンテナ上に構築しています。構築方法や挑戦したことなどを以下のブログにまとめたので、よろしければご覧になってください。
参考
- DjangoでNginxのX-Accel-Redirectを使って、保護されたコンテンツを配信する方法
- 会員サイトで画像ファイルにもアクセス制限をかける方法
- 【Django】画像をアップロードして表示する
- 【Python】PillowのImageをbyte arrayに変換する方法
- はじめてのDjango (7) 画像データの管理やページへの表示,アップロードの方法などについて知ろう
広告
Djangoをやるなら以下の書籍がオススメです。
DjangoでWebアプリを開発するときの要点が分かりやすくまとめられています。
ConoHa VPS
は初期費用不要で月に数百円で利用できる仮想サーバのサービスです。以下のような方には非常にオススメのサービスとなっています!
- 勉強がてらLinuxの環境をちょっと触ってみたい
⇒管理者権限が実行可能なLinuxサーバ環境が構築可能です! - スモールスタートでサービスを提供して、うまくいったら規模をスケールアップしたい
⇒後からメモリサイズやCPU数などのスケールアップ/スケールダウン可能です! - AWSやGCPなどのクラウドサービスは高いので、もっと安くサーバ構築したい
⇒初期費用なし、月数百円(1時間単位も可)で利用可能です!
以上!
コメント
以下のページの管理人です。
Djangoのサイトを載せていただきありがとうございました!!
私もこのページを拝見させていただき勉強になりました。
これからも頑張ってください。
【Django】画像をアップロードして表示する
コメントいただきありがとうございます!
動画のアップロード方法が分かりやすく、
のっくんさんのブログを引用させて頂きました!
はい、お互い頑張りましょうね!