InlineFormの中でautocompleteを使用したい
使い方は通常のadminと同じで、InlineFormのところでもautocomplete_fields
を宣言してあげるだけです。
注意点は、autocomplete_fieldsされる側のadminを用意してあげて、そこでsearch_fields
を宣言してあげる必要があるというのは注意が必要です。
from django.contrib import admin from authors.models import Book class BookInline(admin.StackedInline): autocomplete_fields = ('publisher',) model = Book extra = 1 @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): inlines = (BookInline, )
InlineFormの一覧のソート順を決めたい
新規作成時は問題ないのですが、編集時にInlineFormのオブジェクト一覧の順番が整列していて欲しい場合があります。
そんな時には、こちらも通常のadmin同様、orderingを指定してあげましょう。
from django.contrib import admin from authors.models import Book class BookInline(admin.StackedInline): ordering = ('-pk',) model = Book extra = 1 @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): inlines = (BookInline, )
InlineFormを使用したtestcaseが通らない
InlineFormを使用してadmin側のテストを使用とすると、テストが通りません。extraを0にしても通らず以下のようなエラーが出ます。
django.core.exceptions.ValidationError: ['ManagementForm data is missing or has been tampered with'] (django.core.exceptions.ValidationError: ['マネジメントフォームのデータが見つからないか、改竄されています。'])
これは、InlineFormの方で4つのhiddenの値があり、それらをセットしていない為です。
その値とは、ForeignKeyのrelated_nameとして指定した名称に+して、-TOTAL_FORMS
、-INITIAL_FORMS
、-MAX_NUM_FORMS
、-MIN_NUM_FORMS
という値を渡す必要があります。
model
from django.db import models class Author(models.Model): name = models.CharField(max_length=1024) created = models.DateTimeField(auto_now_add=True) class Book(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books') created = models.DateTimeField(auto_now_add=True)
admin
from django.contrib import admin from authors.models import Author, Book class BookInline(admin.StackedInline): model = Book extra = 1 @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): inlines = (BookInline, )
testcase
from django.test.testcases import TestCase class AuthorAdminTest(TestCase): def test_form(self): self.client.login(username='test', password='test') data = { 'name': 'author name, 'books-TOTAL_FORMS': '0', 'books-INITIAL_FORMS': '0', 'books-MAX_NUM_FORMS': '1', 'books-MIN_NUM_FORMS': '0', } res = self.client.post( managing_reverse('admin:authors_author_add'), data=data, ) self.assertEqual(res.status_code, 302)
これらの値を入れることでテストは通るようになります。結構知らないと悩みの種になったりします。
InlineFormを使うのは便利なんですが、こういう時にはどうしたら良いんだろうみたいなことが纏まってるといいなと思い、これからも何か新しい知見があれば追記していきたいと思います。