Django admin でモデル追加フォームのテンプレートを自由にカスタマイズする方法


admin.ModelAdmin.add_form_template は、Django 管理画面におけるモデル追加フォームのテンプレートをカスタマイズするための属性です。デフォルトでは、Django はモデル定義に基づいてテンプレートを自動生成しますが、この属性を使用することで、独自のテンプレートファイルを使用してフォームのレイアウトや表示内容を制御することができます。

使い方

add_form_template 属性には、テンプレートファイルのパスを文字列として設定します。テンプレートファイルは、プロジェクトの templates ディレクトリ内に配置する必要があります。

from django.contrib import admin

class MyModelAdmin(admin.ModelAdmin):
    add_form_template = 'my_app/admin/add_form.html'

上記の例では、my_app アプリの admin ディレクトリにある add_form.html テンプレートファイルが使用されます。

テンプレートの構造

add_form.html テンプレートファイルには、以下の要素を含めることができます。

  • JavaScript と CSS: フォームの動作や外観をカスタマイズするために、JavaScript と CSS を追加することができます。
  • サイドバー: フォームの横にカスタムコンテンツを追加することができます。
  • ヘッダーとフッター: フォームの上部と下部にカスタムコンテンツを追加することができます。
  • フォームフィールド: Django の標準的なテンプレートタグを使用して、フォームフィールドをレンダリングすることができます。

以下の例は、add_form.html テンプレートファイルの例です。

{% extends 'admin/base.html' %}

{% block content %}
<h1>モデル追加</h1>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">保存</button>
</form>

{% endblock %}

このテンプレートファイルは、Django の標準的な admin/base.html テンプレートを継承しており、以下の要素を含んでいます。

  • 送信ボタン: フォームを送信するためのボタン
  • フォーム: Django の form.as_p テンプレートタグを使用してフォームフィールドをレンダリング
  • ヘッダー: "モデル追加" というタイトル
  • テンプレートファイル内で、モデルインスタンスにアクセスするには、context['object'] 変数を使用することができます。
  • admin.ModelAdmin.change_form_template 属性を使用して、モデル編集フォームのテンプレートをカスタマイズすることもできます。


モデル追加フォームのテンプレートをカスタマイズする

{% extends 'admin/base.html' %}

{% block content %}
<h1>モデル追加</h1>

<div class="form-container">
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="form-group">
            <label for="id_name">名前</label>
            {{ form.name }}
        </div>
        <div class="form-group">
            <label for="id_email">メールアドレス</label>
            {{ form.email }}
        </div>
        <button type="submit">保存</button>
    </form>
</div>

{% endblock %}

このテンプレートファイルは、以下の変更を加えています。

  • 送信ボタンを button 要素で装飾しています。
  • 各フォームフィールドに labelinput 要素を個別に配置しています。
  • フォームフィールドを div 要素で囲んで、レイアウトを整理しています。

モデルインスタンスにアクセスする

以下の例は、add_form.html テンプレートファイル内でモデルインスタンスにアクセスする方法を示しています。

{% extends 'admin/base.html' %}

{% block content %}
<h1>モデル追加</h1>

<div class="form-container">
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="form-group">
            <label for="id_name">名前</label>
            {{ form.name }}
        </div>
        <div class="form-group">
            <label for="id_email">メールアドレス</label>
            {{ form.email }}
        </div>
        <p>作成者: {{ context['object'].created_by }}</p>
        <button type="submit">保存</button>
    </form>
</div>

{% endblock %}
  • モデルインスタンスの created_by 属性の値を、フォームの下部に表示しています。
  • context['object'] 変数を使用して、モデルインスタンスにアクセスしています。

以下の例は、add_form.html テンプレートファイルに JavaScript と CSS を追加する方法を示しています。

{% extends 'admin/base.html' %}

{% block head %}
<link rel="stylesheet" href="{{ STATIC_URL }}css/add_form.css">
<script src="{{ STATIC_URL }}js/add_form.js"></script>
{% endblock %}

{% block content %}
<h1>モデル追加</h1>

<div class="form-container">
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="form-group">
            <label for="id_name">名前</label>
            {{ form.name }}
        </div>
        <div class="form-group">
            <label for="id_email">メールアドレス</label>
            {{ form.email }}
        </div>
        <button type="submit">保存</button>
    </form>
</div>

{% endblock %}
  • CSS ファイルを使用して、フォームの外観をカスタマイズすることができます。
  • JavaScript ファイルを使用して、フォームの動作をカスタマイズすることができます。
  • head ブロック内で、add_form.css スタイルシートと add_form.js JavaScript ファイルを読み込んでいます。


ModelForm を使用してフォームをカスタマイズする

ModelForm を使用してフォームをカスタマイズすることで、テンプレートを変更せずにフォームのレイアウトや表示内容を制御することができます。

from django.forms import ModelForm

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        fields = ['name', 'email']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['name'].widget = forms.TextInput(attrs={'class': 'form-control'})
        self.fields['email'].widget = forms.EmailInput(attrs={'class': 'form-control'})

上記の例では、MyModelForm クラスを作成して、MyModel モデルの nameemail フィールドをカスタマイズしています。

FormMixin を使用してフォームをカスタマイズする

FormMixin を使用してフォームをカスタマイズすることで、テンプレートを変更せずにフォームの動作を制御することができます。

from django.forms import BaseFormMixin

class MyFormMixin(BaseFormMixin):
    def get_form(self, request, *args, **kwargs):
        form = super().get_form(request, *args, **kwargs)
        form.fields['name'].widget = forms.TextInput(attrs={'class': 'form-control'})
        form.fields['email'].widget = forms.EmailInput(attrs={'class': 'form-control'})
        return form

上記の例では、MyFormMixin クラスを作成して、get_form メソッドをオーバーライドしています。このメソッド内で、nameemail フィールドのウィジェットをカスタマイズしています。

Formset を使用してフォームセットをカスタマイズする

Formset を使用してフォームセットをカスタマイズすることで、テンプレートを変更せずにフォームセットのレイアウトや表示内容を制御することができます。

from django.forms import modelformset_factory

MyModelFormSet = modelformset_factory(MyModel, fields=['name', 'email'])

def my_view(request):
    if request.method == 'POST':
        formset = MyModelFormSet(request.POST)
        if formset.is_valid():
            formset.save()
    else:
        formset = MyModelFormSet()

    return render(request, 'my_template.html', {'formset': formset})

上記の例では、MyModelFormSet クラスを作成して、MyModel モデルの nameemail フィールドを含むフォームセットを定義しています。my_view 関数は、POST リクエストの場合にフォームセットを検証し、保存します。GET リクエストの場合には、空のフォームセットを作成してテンプレートにレンダリングします。

JavaScript を使用してフォームをカスタマイズする

JavaScript を使用してフォームをカスタマイズすることで、テンプレートを変更せずにフォームの動作を動的に制御することができます。

{% extends 'admin/base.html' %}

{% block content %}
<h1>モデル追加</h1>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <div class="form-group">
        <label for="id_name">名前</label>
        {{ form.name }}
    </div>
    <div class="form-group">
        <label for="id_email">メールアドレス</label>
        {{ form.email }}
    </div>
    <button type="submit">保存</button>
</form>

<script>
    $(document).ready(function() {
        $('#id_name').focus();

        $('#form').submit(function(event) {
            event.preventDefault();

            if ($('#id_name').val() === '') {
                alert('名前を入力してください');
                return false;
            }

            if ($('#id_email').val() === '') {
                alert('メールアドレスを入力してください');
                return false;
            }

            // フォームを送信
            $(this).submit();
        });
    });
</script>

{% endblock %}

上記の例では、JavaScript を使用して、以下の操作を行っています。

  • フォームロード時に name フィールドにフォーカスを設定します