From 79cd97c47a31c641c9f3ff7704ddf76fe4e9ed17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Fri, 16 Feb 2024 07:28:26 +0100 Subject: [PATCH] Add a get_child_inlines() hook to inline admin classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jesús Leganés-Combarro 'piranna Co-authored-by: Brian Kohan --- .gitignore | 1 + AUTHORS.md | 1 + docs/changelog.rst | 1 + justfile | 2 +- src/polymorphic/admin/inlines.py | 12 +++++++++++- src/polymorphic/tests/admin.py | 26 ++++++++++++++++---------- src/polymorphic/tests/debug.py | 3 +++ src/polymorphic/tests/settings.py | 1 + src/polymorphic/tests/test_admin.py | 12 +++++++++--- 9 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 src/polymorphic/tests/debug.py diff --git a/.gitignore b/.gitignore index da95b94..fa6dc36 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,4 @@ __marimo__/ test1.db test2.db +example/example.db diff --git a/AUTHORS.md b/AUTHORS.md index df7f28c..662a55d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -36,6 +36,7 @@ * Jacob Rief * James Murty * Jedediah Smith (proxy models support) +* Jesús Leganés-Combarro (Auto-discover child models and inlines, #582) * John Furr * Jonas Haag * Jonas Obrist diff --git a/docs/changelog.rst b/docs/changelog.rst index c6465e5..fc6f80d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,7 @@ Changelog v4.3.0 (202X-XX-XX) ------------------- +* Implemented `Include get_child_inlines() hook in stacked inline admin forms. `_ * Fixed `"multi-database support in inheritance accessors. `_ * Fixed `Caching in inheritance accessor functions `_ * Fixed `Foreign key resolves to parent class when using abstract models `_ diff --git a/justfile b/justfile index b5969ac..a7a6966 100644 --- a/justfile +++ b/justfile @@ -15,7 +15,7 @@ manage *COMMAND: import sys from django.core import management sys.path.append(os.getcwd()) - os.environ["DJANGO_SETTINGS_MODULE"] = "polymorphic.tests.settings" + os.environ["DJANGO_SETTINGS_MODULE"] = "polymorphic.tests.debug" os.environ["SQLITE_DATABASES"] = "test1.db,test2.db" management.execute_from_command_line(sys.argv + "{{ COMMAND }}".split(" ")) diff --git a/src/polymorphic/admin/inlines.py b/src/polymorphic/admin/inlines.py index 00fd29d..dcde14f 100644 --- a/src/polymorphic/admin/inlines.py +++ b/src/polymorphic/admin/inlines.py @@ -77,12 +77,22 @@ class PolymorphicInlineModelAdmin(InlineModelAdmin): for child_inline in self.child_inline_instances: self._child_inlines_lookup[child_inline.model] = child_inline + def get_child_inlines(self): + """ + Return the derived inline classes which this admin should handle. + + This should return an iterable of + :class:`~polymorphic.admin.inlines.PolymorphicInlineModelAdmin.Child classes, + to override :attr:`child_inlines. + """ + return self.child_inlines or [] + def get_child_inline_instances(self): """ :rtype List[PolymorphicInlineModelAdmin.Child] """ instances = [] - for ChildInlineType in self.child_inlines: + for ChildInlineType in self.get_child_inlines(): instances.append(ChildInlineType(parent_inline=self)) return instances diff --git a/src/polymorphic/tests/admin.py b/src/polymorphic/tests/admin.py index bcb9e83..0eec077 100644 --- a/src/polymorphic/tests/admin.py +++ b/src/polymorphic/tests/admin.py @@ -1,3 +1,4 @@ +from inspect import isclass from django.contrib.admin import register, ModelAdmin, site as admin_site from polymorphic.admin import ( StackedPolymorphicInline, @@ -35,20 +36,25 @@ class PlainAAdmin(ModelAdmin): search_fields = ["field1"] -class InlineModelAChild(StackedPolymorphicInline.Child): - model = InlineModelA - - -class InlineModelBChild(StackedPolymorphicInline.Child): - model = InlineModelB - autocomplete_fields = ["plain_a"] - - class Inline(StackedPolymorphicInline): model = InlineModelA - child_inlines = (InlineModelAChild, InlineModelBChild) + + def get_child_inlines(self): + return [ + child + for child in self.__class__.__dict__.values() + if isclass(child) and issubclass(child, StackedPolymorphicInline.Child) + ] + + class InlineModelAChild(StackedPolymorphicInline.Child): + model = InlineModelA + + class InlineModelBChild(StackedPolymorphicInline.Child): + model = InlineModelB + autocomplete_fields = ["plain_a"] @register(InlineParent) class InlineParentAdmin(PolymorphicInlineSupportMixin, ModelAdmin): inlines = (Inline,) + extra = 1 diff --git a/src/polymorphic/tests/debug.py b/src/polymorphic/tests/debug.py new file mode 100644 index 0000000..288ad65 --- /dev/null +++ b/src/polymorphic/tests/debug.py @@ -0,0 +1,3 @@ +from .settings import * + +DEBUG = True diff --git a/src/polymorphic/tests/settings.py b/src/polymorphic/tests/settings.py index 2138360..26a6fbd 100644 --- a/src/polymorphic/tests/settings.py +++ b/src/polymorphic/tests/settings.py @@ -101,6 +101,7 @@ INSTALLED_APPS = ( "polymorphic", "polymorphic.tests", ) + MIDDLEWARE = ( "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", diff --git a/src/polymorphic/tests/test_admin.py b/src/polymorphic/tests/test_admin.py index 444eb83..904a38e 100644 --- a/src/polymorphic/tests/test_admin.py +++ b/src/polymorphic/tests/test_admin.py @@ -93,6 +93,15 @@ class PolymorphicAdminTests(AdminTestCase): self.admin_post_delete(Model2A, d_obj.pk) pytest.raises(Model2A.DoesNotExist, (lambda: d_obj.refresh_from_db())) + def test_get_child_inlines(self): + from .admin import Inline + + inline = Inline(parent_model=InlineParent, admin_site=admin.site) + child_inlines = inline.get_child_inlines() + self.assertEqual(len(child_inlines), 2) + self.assertEqual(child_inlines[0], Inline.InlineModelAChild) + self.assertEqual(child_inlines[1], Inline.InlineModelBChild) + def test_admin_inlines(self): """ Test the registration of inline models. @@ -205,9 +214,6 @@ class _GenericAdminFormTest(StaticLiveServerTestCase): def setUp(self): """Create an admin user before running tests.""" - self.admin_username = "admin" - self.admin_password = "password" - self.page = self.browser.new_page() # Log in to the Django admin self.page.goto(f"{self.live_server_url}/admin/login/")