summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/admin/options.py4
-rw-r--r--docs/releases/1.8.6.txt3
-rw-r--r--tests/admin_views/admin.py27
-rw-r--r--tests/admin_views/models.py11
-rw-r--r--tests/admin_views/tests.py8
5 files changed, 40 insertions, 13 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 8176926acb..65653a6967 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -485,8 +485,10 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
)
for related_object in related_objects:
related_model = related_object.related_model
+ remote_field = related_object.field.rel
if (any(issubclass(model, related_model) for model in registered_models) and
- related_object.field.rel.get_related_field() == field):
+ hasattr(remote_field, 'get_related_field') and
+ remote_field.get_related_field() == field):
return True
return False
diff --git a/docs/releases/1.8.6.txt b/docs/releases/1.8.6.txt
index 3383e253d0..fef0e7c2d0 100644
--- a/docs/releases/1.8.6.txt
+++ b/docs/releases/1.8.6.txt
@@ -48,3 +48,6 @@ Bugfixes
* Fixed a regression in ``URLValidator`` that allowed URLs with consecutive
dots in the domain section (like ``http://example..com/``) to pass
(:ticket:`25620`).
+
+* Fixed a crash with ``GenericRelation`` and
+ ``BaseModelAdmin.to_field_allowed`` (:ticket:`25622`).
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index b4e67f0a23..3cd3b6147c 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -30,18 +30,19 @@ from .models import (
EmptyModelHidden, EmptyModelMixin, EmptyModelVisible, ExplicitlyProvidedPK,
ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost,
FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gadget, Gallery,
- Grommet, ImplicitlyGeneratedPK, Ingredient, InlineReference, InlineReferer,
- Inquisition, Language, Link, MainPrepopulated, ModelWithStringPrimaryKey,
- NotReferenced, OldSubscriber, OtherStory, Paper, Parent,
- ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot,
- PlotDetails, PluggableSearchPerson, Podcast, Post, PrePopulatedPost,
- PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo, Question, Recipe,
- Recommendation, Recommender, ReferencedByInline, ReferencedByParent,
- RelatedPrepopulated, Report, Reservation, Restaurant,
- RowLevelChangePermissionModel, Section, ShortMessage, Simple, Sketch,
- State, Story, StumpJoke, Subscriber, SuperVillain, Telegram, Thing,
- Topping, UnchangeableObject, UndeletableObject, UnorderedObject,
- UserMessenger, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
+ GenRelReference, Grommet, ImplicitlyGeneratedPK, Ingredient,
+ InlineReference, InlineReferer, Inquisition, Language, Link,
+ MainPrepopulated, ModelWithStringPrimaryKey, NotReferenced, OldSubscriber,
+ OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona,
+ Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post,
+ PrePopulatedPost, PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo,
+ Question, Recipe, Recommendation, Recommender, ReferencedByGenRel,
+ ReferencedByInline, ReferencedByParent, RelatedPrepopulated, Report,
+ Reservation, Restaurant, RowLevelChangePermissionModel, Section,
+ ShortMessage, Simple, Sketch, State, Story, StumpJoke, Subscriber,
+ SuperVillain, Telegram, Thing, Topping, UnchangeableObject,
+ UndeletableObject, UnorderedObject, UserMessenger, Villain, Vodcast,
+ Whatsit, Widget, Worker, WorkHour,
)
@@ -932,6 +933,8 @@ site.register(ReferencedByParent)
site.register(ChildOfReferer)
site.register(ReferencedByInline)
site.register(InlineReferer, InlineRefererAdmin)
+site.register(ReferencedByGenRel)
+site.register(GenRelReference)
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
# That way we cover all four cases:
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index 845d3d9ee2..985a2f6cc3 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -891,3 +891,14 @@ class ExplicitlyProvidedPK(models.Model):
class ImplicitlyGeneratedPK(models.Model):
name = models.IntegerField(unique=True)
+
+
+# Models for #25622
+class ReferencedByGenRel(models.Model):
+ content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
+ object_id = models.PositiveIntegerField()
+ content_object = GenericForeignKey('content_type', 'object_id')
+
+
+class GenRelReference(models.Model):
+ references = GenericRelation(ReferencedByGenRel)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 8e3255c99b..1997e01545 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -640,6 +640,14 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
response = self.client.get(reverse('admin:admin_views_referencedbyinline_changelist'), {TO_FIELD_VAR: 'name'})
self.assertEqual(response.status_code, 200)
+ # #25622 - Specifying a field of a model only referred by a generic
+ # relation should raise DisallowedModelAdminToField.
+ url = reverse('admin:admin_views_referencedbygenrel_changelist')
+ with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls:
+ response = self.client.get(url, {TO_FIELD_VAR: 'object_id'})
+ self.assertEqual(response.status_code, 400)
+ self.assertEqual(len(calls), 1)
+
# We also want to prevent the add, change, and delete views from
# leaking a disallowed field value.
with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls: