Commit 1d8eb0ca authored by Malcolm Box's avatar Malcolm Box Committed by Tim Graham
Browse files

Fixed #25374 -- Made ModelAdmin checks work on instances instead of classes.

This allows dynamically-generated attributes to be specified in
checked ModelAdmin attributes without triggering errors.
parent cf99bae5
Loading
Loading
Loading
Loading
+257 −256

File changed.

Preview size limit exceeded, changes collapsed.

+2 −3
Original line number Diff line number Diff line
@@ -109,9 +109,8 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
    show_full_result_count = True
    checks_class = BaseModelAdminChecks

    @classmethod
    def check(cls, model, **kwargs):
        return cls.checks_class().check(cls, model, **kwargs)
    def check(self, **kwargs):
        return self.checks_class().check(self, **kwargs)

    def __init__(self):
        overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy()
+4 −3
Original line number Diff line number Diff line
@@ -103,11 +103,12 @@ class AdminSite(object):
                    options['__module__'] = __name__
                    admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)

                # Instantiate the admin class to save in the registry
                admin_obj = admin_class(model, self)
                if admin_class is not ModelAdmin and settings.DEBUG:
                    system_check_errors.extend(admin_class.check(model))
                    system_check_errors.extend(admin_obj.check())

                # Instantiate the admin class to save in the registry
                self._registry[model] = admin_class(model, self)
                self._registry[model] = admin_obj

    def unregister(self, model_or_iterable):
        """
+14 −14
Original line number Diff line number Diff line
@@ -15,55 +15,55 @@ from django.forms.models import modelform_defines_fields


class GenericInlineModelAdminChecks(InlineModelAdminChecks):
    def _check_exclude_of_parent_model(self, cls, parent_model):
    def _check_exclude_of_parent_model(self, obj, parent_model):
        # There's no FK to exclude, so no exclusion checks are required.
        return []

    def _check_relation(self, cls, parent_model):
    def _check_relation(self, obj, parent_model):
        # There's no FK, but we do need to confirm that the ct_field and ct_fk_field are valid,
        # and that they are part of a GenericForeignKey.

        gfks = [
            f for f in cls.model._meta.virtual_fields
            f for f in obj.model._meta.virtual_fields
            if isinstance(f, GenericForeignKey)
        ]
        if len(gfks) == 0:
            return [
                checks.Error(
                    "'%s.%s' has no GenericForeignKey." % (
                        cls.model._meta.app_label, cls.model._meta.object_name
                        obj.model._meta.app_label, obj.model._meta.object_name
                    ),
                    hint=None,
                    obj=cls,
                    obj=obj.__class__,
                    id='admin.E301'
                )
            ]
        else:
            # Check that the ct_field and ct_fk_fields exist
            try:
                cls.model._meta.get_field(cls.ct_field)
                obj.model._meta.get_field(obj.ct_field)
            except FieldDoesNotExist:
                return [
                    checks.Error(
                        "'ct_field' references '%s', which is not a field on '%s.%s'." % (
                            cls.ct_field, cls.model._meta.app_label, cls.model._meta.object_name
                            obj.ct_field, obj.model._meta.app_label, obj.model._meta.object_name
                        ),
                        hint=None,
                        obj=cls,
                        obj=obj.__class__,
                        id='admin.E302'
                    )
                ]

            try:
                cls.model._meta.get_field(cls.ct_fk_field)
                obj.model._meta.get_field(obj.ct_fk_field)
            except FieldDoesNotExist:
                return [
                    checks.Error(
                        "'ct_fk_field' references '%s', which is not a field on '%s.%s'." % (
                            cls.ct_fk_field, cls.model._meta.app_label, cls.model._meta.object_name
                            obj.ct_fk_field, obj.model._meta.app_label, obj.model._meta.object_name
                        ),
                        hint=None,
                        obj=cls,
                        obj=obj.__class__,
                        id='admin.E303'
                    )
                ]
@@ -71,16 +71,16 @@ class GenericInlineModelAdminChecks(InlineModelAdminChecks):
            # There's one or more GenericForeignKeys; make sure that one of them
            # uses the right ct_field and ct_fk_field.
            for gfk in gfks:
                if gfk.ct_field == cls.ct_field and gfk.fk_field == cls.ct_fk_field:
                if gfk.ct_field == obj.ct_field and gfk.fk_field == obj.ct_fk_field:
                    return []

            return [
                checks.Error(
                    "'%s.%s' has no GenericForeignKey using content type field '%s' and object ID field '%s'." % (
                        cls.model._meta.app_label, cls.model._meta.object_name, cls.ct_field, cls.ct_fk_field
                        obj.model._meta.app_label, obj.model._meta.object_name, obj.ct_field, obj.ct_fk_field
                    ),
                    hint=None,
                    obj=cls,
                    obj=obj.__class__,
                    id='admin.E304'
                )
            ]
+3 −0
Original line number Diff line number Diff line
@@ -1064,6 +1064,9 @@ Miscellaneous
* By default :class:`~django.test.LiveServerTestCase` attempts to find an
  available port in the 8081-8179 range instead of just trying port 8081.

* The system checks for :class:`~django.contrib.admin.ModelAdmin` now check
  instances rather than classes.

.. _deprecated-features-1.9:

Features deprecated in 1.9
Loading