DjangoAdminでInlineFormを使用する際のテクニック色々

Django

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を使うのは便利なんですが、こういう時にはどうしたら良いんだろうみたいなことが纏まってるといいなと思い、これからも何か新しい知見があれば追記していきたいと思います。

コメントを残す