From 37f92b3a3f86d7929afbb6f823316a27cd1a7624 Mon Sep 17 00:00:00 2001 From: James Murty Date: Thu, 13 Oct 2016 09:35:13 +1100 Subject: [PATCH] Fix get parent admin when intermediate not root ctype model is registered This change fixes an issue where django-polymorphic raises a `ParentAdminNotRegistered` exception when you register an admin for a child model ancestor, but not for the root ancestor as pointed to by the `polymorphic_ctype` field. This error occurs only when you *Save* the child model detail form, not when you *Save and continue* on that same form. This situation occurs for us when using django-fluent-pages version 1.0.1 which has an intermediate `Page` model registered with a parent admin to show the pages listing. The existing `_get_parent_admin` method expects an admin to be registered for the root `UrlNode` model pointed to by the `polymorphic_ctype` field. This fix uses a potentially naive and slow brute-force approach where it walks up the class hierarchy and checks whether a parent admin is registered for each ancestor model, unless/until it finds one. See also https://github.com/ic-labs/django-icekit/issues/31/ --- polymorphic/admin/childadmin.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/polymorphic/admin/childadmin.py b/polymorphic/admin/childadmin.py index c6ce41c..11caa22 100644 --- a/polymorphic/admin/childadmin.py +++ b/polymorphic/admin/childadmin.py @@ -1,12 +1,15 @@ """ The child admin displays the change/delete view of the subclass model. """ +import inspect + from django.contrib import admin from django.core.urlresolvers import resolve from django.utils import six from django.utils.translation import ugettext_lazy as _ from .helpers import PolymorphicInlineSupportMixin +from ..admin import PolymorphicParentModelAdmin class ParentAdminNotRegistered(RuntimeError): @@ -123,6 +126,21 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin): try: return self.admin_site._registry[parent_model] except KeyError: + # Admin is not registered for polymorphic_ctype model, but it may + # be registered for a model in the class ancestry between this + # model and the root parent one. + for klass in inspect.getmro(self.model): + # Ignore model ancestors that are not also subclasses of the + # target ctype model + if not issubclass(klass, parent_model): + continue + # Fetch admin instance for model class (may return None) + model_admin = self.admin_site._registry.get(klass) + # Ignore admin (or None) that isn't a polymorphic parent admin + if not isinstance(model_admin, PolymorphicParentModelAdmin): + continue + return model_admin # Success! + # If we get this far without returning there is no admin available raise ParentAdminNotRegistered("No parent admin was registered for a '{0}' model.".format(parent_model)) def response_post_save_add(self, request, obj):