ホーム >  Python > Django >  Djangoで画像アップローダを作る

投稿日:   |  最終更新日:

Djangoで画像アップローダを作る

DjangoPython

Djangoで画像のアップロード機能を作成します。

画像アップローダ

画像ファイルを指定します。送信ボタンをクリックするとDjangoのディレクトリ内に指定した画像がアップロードされる仕組みです。

画像をWEBアプリで管理するには?

以下の2つの方法があります。

  • ①画像データそのものをデータベースに保存。
  • ②画像のパスをデータベースに保存。

①の画像データそのものをデータベースに保存することは可能ですが、容量がどんどん増大してしまいます。②の方法を取るパターンが一般的です。

保存場所の作成

画像をWEBアプリにアップロードする場合、メディアファイルを格納するディレクトリ(メディアルートと呼ぶ)が必要になります。開発環境ではプロジェクトルート(私の例ではpj1)直下にmediaというディレクトリを作りメディアルートとするのが一般的です。

※作成後はプロジェクトの.gitignoreを修正してバージョン管理から除外します。また、本番環境ではAmazon S3のバゲットのような外部ストレージを利用します。

URL設計

トップページ
(/index)
ドメイン直下のページです。ログイン前はページタイトルのみですが、ログインすると、ヘッダーナビゲーションにログアウトのリンクを表示します。
画像アップローダ
(/photoupload)
今回作成するページです。「参照」ボタンをクリックするとローカルにある画像選択が表示されます。選択して「投稿」ボタンをクリックすると画像がアップロードされてトップページへ遷移します。

仕様

①トップページです。「ドメイン/」にアクセスします。画面右上にログインページへのリンクがあります。

②画像アップロードページです。「ドメイン/photoupload」にアクセスします。

③「参照:」ボタンをクリックすると、画像選択が表示されます。これはhtmlのコードで可能です。

④画像選択が完了すると、ファイル名が参照ボタンの横に表示されます。最後に「投稿」ボタンをクリックしてアップロードを実行します。

⑤djangoプロジェクトの「media/images」ディレクトリに画像がアップロードされます。

  • pj1/
  • media/
  • images/
  • xxx.jpeg
  • pj1/
  • __init__.py
  • settings.py
  • urls.py
  • wsgi.py
  • users/
  • __init__.py
  • admin.py
  • apps.py
  • urls.py
  • views.py
  • models.py
  • templates/
  • index.html
  • users/
  • photoupload.html
  • manage.py

⑥postbackが成功すると、index(トップページ)にリダイレクトします。

準備

当サイトでは、Vagrantでゲスト環境(仮想環境)を作ってDjangoを動かいていますが、それ以外の環境でも操作方法はだいたい同じです。

①Djangoプロジェクトを生成します。

VagrantのDjangoで作るWebアプリケーション(その1 プロジェクト生成)

②Djangoアプリケーションを作ります。

VagrantのDjangoで作るWebアプリケーション(その2 プロジェクトの初期設定)

環境

OS CentOS 7.1.1503
pyenv 1.1.3-5-g7dae197
Anaconda 3-4.3.0
MariaDB 5.5.52-1.el7
Apache 2.4.6
mod_wsgi 4.6.3
Django 2.0.3


画像アップローダ機能概要

①以下のようなDjangoアプリ構成を作ります。プロジェクト名が「pj1」で、アプリケーション名が「users」です。プロジェクトの設定は済ませたものとします。赤字のファイルは、今回変更する部分です。

  • pj1/
  • media/
  • pj1/
  • __init__.py
  • settings.py
  • urls.py
  • wsgi.py
  • users/
  • __init__.py
  • admin.py
  • apps.py
  • urls.py
  • views.py
  • models.py
  • templates/
  • index.html
  • users/
  • photoupload.html
  • manage.py

Pillowインストール

①ImageFieldの使用にPillowが必要なのでPillowもインストール済みの前提です。以下のコマンドでインストールします。

pip install Pillow==5.0.0

プロジェクト/settings.py

pj1ディレクトリ下のsettings.pyを変更します。

①画像ファイルのパスのルート用に「MEDIA_ROOT」を設定します。また、 画像ファイルのURLのルート用に「MEDIA_URL」を定義します。

STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

プロジェクト/urls.py

pj1ディレクトリ下のurls.pyを変更します。

①ユーザーが画像にアクセス出来るように、プロジェクトのURLパターンにメディアの設定を加えます。

from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
url(r'^admin/', admin.site.urls),
]

# 以下を定義
from django.conf import settings
from django.conf.urls.static import static

if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

モデルの定義

モデルを定義します。

①Photoというモデルを定義します。

myapp/models.py
from django.db import models

class Photo(models.Model):
image = models.ImageField(upload_to='images/', verbose_name="画像", )

②定義後は必ずマイグレーションを実行します。

python manage.py makemigrations
python manage.py migrate

解説

Photoのimageフィールドのupload_toで指定するパスは、内部的にMEDIA_ROOTと結合されます。また、途中のディレクトリは画像保存時に自動で作成されます。今回はmyappというディレクトリを指定しています。

ImageField

ImageFieldは、画像を扱うことに特化したFileFieldの派生フィールドです。ImageFieldの利用には追加パッケージとしてPillowが要求されます。
データを登録すると、MEDIA_ROOT配下のupload_toの場所にファイルが保存されます。

ImageFieldとFileFieldの違い

ImageField:登録時のバリデーションで画像ファイルのチェックします。画像ファイルでないもの、データの破損があるものは登録エラーが発生します(専用エラーメッセージあり)。

FileField:管理用のフィールドを事前に用意すると、登録時に画像の高さと幅(pixel単位)を取得して保存します。


フォームの定義

フォームを定義します。

①アプリケーションのディレクトリにforms.pyを作成し定義します。

from django import forms

class PhotoForm(forms.Form):

    image = forms.ImageField()

アプリケーション/views.py

アプリケーション(users)のビューに処理を書きます。

from django.shortcuts import render, redirect
from .forms import PhotoForm
from .models import Photo

def index(request):
  context = {
    'photos': Photo.objects.all(),
  }

def photoupload(req):
       if req.method == 'GET':
        return render(req, 'users/photoupload.html', {
        'form': PhotoForm(),
   })

    elif req.method == 'POST':
        form = PhotoForm(req.POST, req.FILES)
        if not form.is_valid():
           raise ValueError('invalid form')

        photo = Photo()
        photo.image = form.cleaned_data['image']
        photo.save()

        return redirect('/')

解説

フォームから画像をアップロードすると「/media/」ディレクトリ以下に画像が保存されます。

また、テンプレートファイルはphotoupload.htmlを利用します。

アップロード後、index(トップページ)にリダイレクトします。ここでアップロードした画像を表示するために以下のようにコンテキストにフォームを渡しています。

def index(request):
  context = {
    'photos': Photo.objects.all(),
  }


テンプレート作成

htmlのテンプレートファイルを作成します。

<form action="{% url 'index' %}" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="投稿">
</form># アップローダ

解説

画像の送信にはenctypeの指定が必要です。これが無いとviews.pyの「form.is_valid」で不正になります。

actionにはindexビューへのネームを指定しています。


アプリケーション/urls.py

①urls.pyに、以下のurlを設定します。

from django.conf.urls import url                                                   
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^photoupload/$', views.photoupload, name='photoupload'),
]

画像の表示

アップロードした画像を表示します。

①views.pyでindexにコンテキストを指定しました。あとはhtml側で以下のように記述します。

{% for p in photos %}
    <div>
        <img src="{{ p.image.url }}" />                                           
    </div>
{% endfor %}

次回

コメントに対するコメントのためのフォームを作ります。

コメント投稿に対してコメント投稿するページを作る(Django)


トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター、フロントエンドエンジニア 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 20

最近の投稿
人気記事
カテゴリー
広告