diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2014-03-08 11:24:13 +0800 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2014-03-08 11:25:23 +0800 |
| commit | 70ec4d776ef0e68960ccee21476b8654e9399f53 (patch) | |
| tree | cd4b68aad597845ab8542cb2f2f8a646f75d3b40 /django | |
| parent | 219d928852c256a81d09dbaa29ed4cec42d2fdfa (diff) | |
Fixed #22034 -- Added a specific set of relation checks for GenericInlineModelAdmin.
Thanks to jwa for the report.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/admin/checks.py | 6 | ||||
| -rw-r--r-- | django/contrib/contenttypes/admin.py | 78 |
2 files changed, 81 insertions, 3 deletions
diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py index badc1514cd..dfe4cd04ec 100644 --- a/django/contrib/admin/checks.py +++ b/django/contrib/admin/checks.py @@ -846,7 +846,7 @@ class InlineModelAdminChecks(BaseModelAdminChecks): def check(self, cls, parent_model, **kwargs): errors = super(InlineModelAdminChecks, self).check(cls, model=cls.model, **kwargs) - errors.extend(self._check_fk_name(cls, parent_model)) + errors.extend(self._check_relation(cls, parent_model)) errors.extend(self._check_exclude_of_parent_model(cls, parent_model)) errors.extend(self._check_extra(cls)) errors.extend(self._check_max_num(cls)) @@ -861,7 +861,7 @@ class InlineModelAdminChecks(BaseModelAdminChecks): return [] # Skip if `fk_name` is invalid. - if self._check_fk_name(cls, parent_model): + if self._check_relation(cls, parent_model): return [] if cls.exclude is None: @@ -883,7 +883,7 @@ class InlineModelAdminChecks(BaseModelAdminChecks): else: return [] - def _check_fk_name(self, cls, parent_model): + def _check_relation(self, cls, parent_model): try: _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name) except ValueError as e: diff --git a/django/contrib/contenttypes/admin.py b/django/contrib/contenttypes/admin.py index c67fbca288..8da6546a21 100644 --- a/django/contrib/contenttypes/admin.py +++ b/django/contrib/contenttypes/admin.py @@ -2,19 +2,97 @@ from __future__ import unicode_literals from functools import partial +from django.contrib.admin.checks import InlineModelAdminChecks from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets +from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.forms import ( BaseGenericInlineFormSet, generic_inlineformset_factory ) +from django.core import checks +from django.db.models.fields import FieldDoesNotExist from django.forms import ALL_FIELDS from django.forms.models import modelform_defines_fields +class GenericInlineModelAdminChecks(InlineModelAdminChecks): + def _check_exclude_of_parent_model(self, cls, parent_model): + # There's no FK to exclude, so no exclusion checks are required. + return [] + + def _check_relation(self, cls, 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 + 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 + ), + hint=None, + obj=cls, + id='admin.E301' + ) + ] + else: + # Check that the ct_field and ct_fk_fields exist + try: + cls.model._meta.get_field(cls.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 + ), + hint=None, + obj=cls, + id='admin.E302' + ) + ] + + try: + cls.model._meta.get_field(cls.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 + ), + hint=None, + obj=cls, + id='admin.E303' + ) + ] + + # 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: + 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 + ), + hint=None, + obj=cls, + id='admin.E304' + ) + ] + + class GenericInlineModelAdmin(InlineModelAdmin): ct_field = "content_type" ct_fk_field = "object_id" formset = BaseGenericInlineFormSet + checks_class = GenericInlineModelAdminChecks + def get_formset(self, request, obj=None, **kwargs): if 'fields' in kwargs: fields = kwargs.pop('fields') |
