【Django】ImageFieldの使い方
ImageFieldの使い方のポイント
画像をアップロードする際に、DjangoのmodelでImage Fieldを使う場合があります。
他のFieldと違い設定をする必要があるので、初めて使う人のためにもメモとして残しておきます。
うまくいかないパターンで多いのは、下記のようなことだと思います。
- うまくアップロードされない
- ファイルを選択してPOSTで送ってもなぜか空orNoneになる。
具体的に設定のポイントを押さえておきましょう。
ファイルアップロードのポイント
設定のポイントは、以下の2つです。
- アップロードファイルは、MEDIAフォルダに入る
- HTMLからViewでPOSTで送る際、FILE形式で送る必要がある
MEDIAフォルダの設定
まずは、mediaを設定します。
一般的な配置の方法は、プロジェクト配下にmediaフォルダを新規作成します。。
sampleとしてdjango_projectというプロジェクトに作成すると...
django_project/ ├config/ │ ├ __init__.py │ ├ settings.py │ ├ urls.py │ └ wsgi.py ├django-app/ ├media/ # 新規作成 ├static/ ├templates/ ├ db.sqlite3 └ manage.py
次にsettings.pyの設定を行います。
settings.pyにmediaフォルダの設定を追記します。(一番下に追記してOK)
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, "media")
以上でmediaフォルダの設定が完了です。
ModelとFormの設定
Modelは、ImageFieldを宣言するだけです。
例えば、画像(image)とそれの説明(description)を宣言する場合は、下記のようにします。
class Images(models.Model): image = models.ImageField(upload_to='img/upload') description = models.CharField(null=True, blank=True, max_length=256)
upload_toオプションで指定した文字列は、アップロード先のディレクトリを指します。
上記の例では、media/img/upload/配下に画像が保存されるように設定されています。
Formは、下記のように書けばOKです。
class ImagesForm(forms.ModelForm): class Meta: model = Images fields = ('image', 'description',)
TemplateとViewの設定
templateは、以下のように設定します。
<form method="post" enctype="multipart/form-data"> {% csrf_token %} <table> <tr><td> {{ form.images }} <!-- error表示--> {% if form.errors.image %} <div class="alert alert-danger" role="alert">{{ form.image.errors }}</div> {% endif %} </td></tr> <tr><td> {{ form.description }} <!-- error表示--> {% if form.errors.description %} <div class="alert alert-danger" role="alert">{{ form.description.errors }}</div> {% endif %} </td></tr> <tr><td> <button type="submit">Upload</button> </td></tr> </table> </form>
ポイントは、fromタグに、「enctype="multipart/form-data"」を追記することです。 これで、POSTリクエストを送る際に、フィル形式でサーバーに送ることができます。
続いて、View側の設定です。
今回は、CreateViewを使ったやり方を紹介します。
class ImagesCreateView(CreateView): template_name = 'img/image_form.html' # 上記のTemplateのパス form_class = ImagesForm # 上記のFormを設定 def post(self, request, *args, **kwargs): # リクエストがpostの際の処理をオーバーライドして記載 form = ImagesForm(request.POST, request.FILES) if not form.is_valid(): # validationでエラーがあれば、formに戻る(エラーメッセージを返す) return render(request, self.template_name, {'form': form}, ) form.save() # formを保存 return redirect(reverse('image:index')) # 成功した際の遷移先
上記のポイントは、postを受け取った際に、FILESを受け取ることです。
この記述があることで、ファイルを受け取ります。
form = ImagesForm(request.POST, request.FILES)
以上で、formからファイルをアップロードできる設定は完了です。
試しに、動かしてみましょう。
※もし、不具合等あれば、コメント欄にてお願いします。
おまけ1:画像を表示する
uploadした画像を表示する場合は、
templateに以下のように記述することで、表示できます
(modelのパラメータをobjectとした場合)
<img src="{{ object.image.url }}"/>
おまけ2:保存する際のファイル名を変更する
例えば、formにfile_nameを入力して、入力されたファイル名を保存する場合は、以下のように、modelを記述します。
def get_upload_path(instance, filename): return 'img/'+filename class Images(models.Model): file_name = models.CharField(max_length=30) image = models.ImageField(upload_to=get_upload_path)