もう悩まない! Django admin のインラインフォーム表示数を max_num 属性でスマートに制御
django.contrib.admin
モジュール内の admin.InlineModelAdmin.max_num
属性は、Django 管理サイトにおいて、インラインフォーム内に表示される最大フォーム数を制御します。
詳細
max_num
属性を設定すると、以下の影響があります。- 管理サイトで親オブジェクトの編集画面を開いた際、
max_num
個分のインラインフォームが表示されます。 max_num
個を超えるインラインフォームが存在する場合は、それらは非表示になります。- 非表示になったインラインフォームは、
Add another
ボタンをクリックすることで表示できます。 max_num
個のインラインフォームがすべて使用されている場合は、Add another
ボタンは非表示になります。
- 管理サイトで親オブジェクトの編集画面を開いた際、
- 0 以上の値を設定すると、その値が最大フォーム数として設定されます。
- デフォルト値は
0
であり、制限はありません。 max_num
属性は、InlineModelAdmin
クラス内に定義されます。
例
from django.contrib import admin
class BookInline(admin.TabularInline):
model = Book
max_num = 3
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
上記例では、BookInline
インラインフォーム内に最大3個のフォームが表示されます。
max_num
属性は、パフォーマンスにも影響を与える可能性があります。- 多くのインラインフォームを表示する場合は、パフォーマンスが低下する可能性があります。
- 必要に応じて
max_num
属性を調整することをおすすめします。
max_num
属性とextra
属性は併用できます。extra
属性は、追加で表示する空のインラインフォーム数を指定します。max_num
属性とextra
属性を組み合わせることで、常に特定数のインラインフォームを表示することができます。
- 詳細については、Django 公式ドキュメントを参照してください。
- 上記以外にも、
django.contrib.admin
モジュールには様々な機能が用意されています。
max_num 属性と extra 属性の併用
from django.contrib import admin
class BookInline(admin.TabularInline):
model = Book
max_num = 3
extra = 2
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
さらに、2個の空のインラインフォームも追加で表示されます。
結果
- ユーザーは必要に応じて、空のフォームにデータをを入力することができます。
- 最初は 3個 のフォームが表示され、2個 の空のフォームが追加で表示されます。
- 管理サイトで親オブジェクトの編集画面を開いた際、最大5個のインラインフォームが表示されます。
max_num 属性と can_delete 属性の組み合わせ
from django.contrib import admin
class BookInline(admin.TabularInline):
model = Book
max_num = 3
can_delete = False
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
上記例では、BookInline
インラインフォーム内に最大3個のフォームが表示されます。
さらに、削除ボタンが非表示になります。
結果
- ユーザーはフォームを編集することはできますが、削除することはできません。
- 管理サイトで親オブジェクトの編集画面を開いた際、最大3個のインラインフォームが表示されます。
from django.contrib import admin
class BookInline(admin.TabularInline):
model = Book
max_num = 3
def save_formset(self, request, formset, commit=True):
if formset.saved_forms and len(formset.saved_forms) > self.max_num:
# 最大フォーム数を超えた場合は、最後のフォームを削除する
formset.saved_forms.pop()
super().save_formset(request, formset, commit=commit)
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
上記例では、BookInline
インラインフォーム内に最大3個のフォームが表示されます。
さらに、最大フォーム数を超えた場合、最後のフォームが自動的に削除されます。
結果
- しかし、4個目 のフォームを作成すると、1個目 のフォームが自動的に削除されます。
- ユーザーは 3個 以上のフォームを作成することができます。
以下、いくつかの代替方法と、それぞれの利点と欠点をご紹介します。
JavaScript による非表示
- 欠点:
- JavaScript を無効にしているユーザーには表示されてしまう
- SEO に影響を与える可能性がある
- 利点:
- シンプルで実装しやすい
- 柔軟な制御が可能
$(document).ready(function() {
$('.inline-deletable').slice(3).hide();
});
カスタムインラインフォーム
- 欠点:
- 複雑な実装が必要
- コード量が増える
- 利点:
- より柔軟な制御が可能
- コードをカプセル化できる
from django.contrib import admin
class MyInlineFormSet(admin.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.queryset.count() > 3:
for form in self.forms[:self.queryset.count() - 3]:
form.helper.add_hidden_field('DELETE', 'False')
class BookInline(admin.TabularInline):
formset_class = MyInlineFormSet
model = Book
max_num = 0 # max_num を 0 に設定しても、影響を与えない
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
シグナルによる非表示
- 欠点:
- 複雑な実装が必要
- コード量が増える
- 利点:
- 再利用可能なコードを記述できる
- 他のアプリケーションとの統合が容易
from django.dispatch import receiver
from django.contrib import admin
@receiver(admin.ModelAdmin.get_formsets, sender=AuthorAdmin)
def limit_inline_formsets(request, model_admin, queryset):
if model_admin.model == Book:
return {
'inlines': [
BookInline(model_admin, queryset, max_num=3),
],
}
class BookInline(admin.TabularInline):
model = Book
max_num = 0 # max_num を 0 に設定しても、影響を与えない
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
サードパーティ製ライブラリ
- 欠点:
- ライブラリのメンテナンス状況によっては、将来的に利用できなくなる可能性がある
- 利点:
- 既存の機能を利用できる
- 開発時間を短縮できる
from django.contrib import admin
from admin_tools.tools.tabularinline import TabularInlineWithMax
class BookInline(TabularInlineWithMax):
model = Book
max_num = 3
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline,]
最適な代替方法は、状況によって異なります。
上記以外にも、様々な方法で admin.InlineModelAdmin.max_num
の機能を代替することができます。