diff --git a/.gitignore b/.gitignore index da95b94c..fa6dc361 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 df7f28c6..662a55df 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 c6465e54..fc6f80da 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 b5969ac2..a7a69660 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 00fd29d2..dcde14fd 100644 --- a/src/polymorphic/admin/inlines.py +++ b/src/polymorphic/admin/inlines.py @@ -77,12 +77,22 @@ def __init__(self, parent_model, admin_site): 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 bcb9e83b..0eec0774 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): +class Inline(StackedPolymorphicInline): model = InlineModelA + def get_child_inlines(self): + return [ + child + for child in self.__class__.__dict__.values() + if isclass(child) and issubclass(child, StackedPolymorphicInline.Child) + ] -class InlineModelBChild(StackedPolymorphicInline.Child): - model = InlineModelB - autocomplete_fields = ["plain_a"] - + class InlineModelAChild(StackedPolymorphicInline.Child): + model = InlineModelA -class Inline(StackedPolymorphicInline): - model = InlineModelA - child_inlines = (InlineModelAChild, InlineModelBChild) + 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 00000000..288ad651 --- /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 21383603..26a6fbd5 100644 --- a/src/polymorphic/tests/settings.py +++ b/src/polymorphic/tests/settings.py @@ -101,6 +101,7 @@ "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 444eb83a..904a38e2 100644 --- a/src/polymorphic/tests/test_admin.py +++ b/src/polymorphic/tests/test_admin.py @@ -93,6 +93,15 @@ class Model2ChildAdmin(PolymorphicChildModelAdmin): 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 @@ def tearDownClass(cls): 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/")