DjangoAdminでforms.ImageFieldの初期値をmodels.ImageFieldのように

Django

forms.ImageFieldで初期値を表示したい

models.ImageFieldで保存されたデータでは、DjangoAdminで編集する際に、オブジェクトが渡されてURLが表示されるようになっているのですが、これをforms.ImageFieldでやろうとすると、formの__init__関数で初期値を入れてあげることは分かっても、何を渡してあげれば良いのかで困ってしまいました。

まずは自作フォームのおさらい

とりあえず、ModelFormを継承して、オリジナルのフォームも追加してみます。
モデル名Sampleで、Sampleには存在しないフィールド名imgをフォームとして追加してあげる例です。

class SampleForm(forms.ModelForm):
    img = forms.ImageField(
        required=False,
        widget=forms.ClearableFileInput(attrs={'class': 'form-control-file'}),
        label='画像'
    )

    class Meta:
        model = Sample

実際に使用する際には、save関数なりで、imgの値を取り出して何かしてあげる必要があります。

今回、自分がやっていたこととしては、画像ファイルをs3にアップロードして、そのurlのみを別フィールドに保存していました。

forms.ImageFieldに初期値を入れてあげる

上記で作成したSampleFormの__init__関数で初期値を入れます。この際に入れてあげる初期値はImageFieldFileのオブジェクトでなくてはならない

自分の場合は、上記のとおり、imgをurlとして保存していて、それをImageFieldFileに設定すると以下のような感じになりました。もし、models.ImageFieldのオブジェクトを使用して別フィールドを作る際には、instanceに渡せばいいんじゃないかなと思います。

from django import forms
from django.db.models.fields.files import ImageFieldFile, FileField

class SampleForm(forms.ModelForm):
    img = forms.ImageField(
        required=False,
        widget=forms.ClearableFileInput(attrs={'class': 'form-control-file'}),
        label='画像'
    )

    class Meta:
        model = Sample 
     
    def __init__(self, *args, **kwargs):
        super(SampleForm, self).__init__(*args, **kwargs)
        if self.initial:
            self.fields['img'].initial = ImageFieldFile(instance=None, field=FileField(), name=self.instance.data.get('img', '')) <-- 画像のurlをimgに渡してあげる
    

因みにforms.ImageFieldのfieldを、モデルのfield名と同じ名称を使ってoverwriteしようとしたら、上手くいきませんでした。別名をちゃんと指定するようにしましょう。

最後に

意外と需要ありそうなのに、stackoverflowなどでもサンプルがなかなか見つからなく大変でした、、

結局、ImageFieldFileに行き着いた経緯としては、Adminの画像を扱うテンプレート側のwidgetの中身を見たことで、どういった型のものが受け渡されているのかを見て直ぐにImageFieldFileだということが分かったので、最初からこれに気付いていれば簡単な問題でした。。

コメントを残す