summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2014-03-08 11:24:13 +0800
committerRussell Keith-Magee <russell@keith-magee.com>2014-03-08 11:25:23 +0800
commit70ec4d776ef0e68960ccee21476b8654e9399f53 (patch)
treecd4b68aad597845ab8542cb2f2f8a646f75d3b40 /django
parent219d928852c256a81d09dbaa29ed4cec42d2fdfa (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.py6
-rw-r--r--django/contrib/contenttypes/admin.py78
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')