Fixed #25622 -- Accounted for generic relations in the admin to field validation
Thanks to Jonathan Liuti for the report and Tim Graham for the review.
This commit is contained in:
parent
96fe90f535
commit
9dcfecb7c6
|
@ -413,8 +413,10 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
|
||||||
)
|
)
|
||||||
for related_object in related_objects:
|
for related_object in related_objects:
|
||||||
related_model = related_object.related_model
|
related_model = related_object.related_model
|
||||||
|
remote_field = related_object.field.remote_field
|
||||||
if (any(issubclass(model, related_model) for model in registered_models) and
|
if (any(issubclass(model, related_model) for model in registered_models) and
|
||||||
related_object.field.remote_field.get_related_field() == field):
|
hasattr(remote_field, 'get_related_field') and
|
||||||
|
remote_field.get_related_field() == field):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -48,3 +48,6 @@ Bugfixes
|
||||||
* Fixed a regression in ``URLValidator`` that allowed URLs with consecutive
|
* Fixed a regression in ``URLValidator`` that allowed URLs with consecutive
|
||||||
dots in the domain section (like ``http://example..com/``) to pass
|
dots in the domain section (like ``http://example..com/``) to pass
|
||||||
(:ticket:`25620`).
|
(:ticket:`25620`).
|
||||||
|
|
||||||
|
* Fixed a crash with ``GenericRelation`` and
|
||||||
|
``BaseModelAdmin.to_field_allowed`` (:ticket:`25622`).
|
||||||
|
|
|
@ -31,18 +31,19 @@ from .models import (
|
||||||
EmptyModelHidden, EmptyModelMixin, EmptyModelVisible, ExplicitlyProvidedPK,
|
EmptyModelHidden, EmptyModelMixin, EmptyModelVisible, ExplicitlyProvidedPK,
|
||||||
ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost,
|
ExternalSubscriber, Fabric, FancyDoodad, FieldOverridePost,
|
||||||
FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gadget, Gallery,
|
FilteredManager, FooAccount, FoodDelivery, FunkyTag, Gadget, Gallery,
|
||||||
Grommet, ImplicitlyGeneratedPK, Ingredient, InlineReference, InlineReferer,
|
GenRelReference, Grommet, ImplicitlyGeneratedPK, Ingredient,
|
||||||
Inquisition, Language, Link, MainPrepopulated, ModelWithStringPrimaryKey,
|
InlineReference, InlineReferer, Inquisition, Language, Link,
|
||||||
NotReferenced, OldSubscriber, OtherStory, Paper, Parent,
|
MainPrepopulated, ModelWithStringPrimaryKey, NotReferenced, OldSubscriber,
|
||||||
ParentWithDependentChildren, Person, Persona, Picture, Pizza, Plot,
|
OtherStory, Paper, Parent, ParentWithDependentChildren, Person, Persona,
|
||||||
PlotDetails, PluggableSearchPerson, Podcast, Post, PrePopulatedPost,
|
Picture, Pizza, Plot, PlotDetails, PluggableSearchPerson, Podcast, Post,
|
||||||
PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo, Question, Recipe,
|
PrePopulatedPost, PrePopulatedPostLargeSlug, PrePopulatedSubPost, Promo,
|
||||||
Recommendation, Recommender, ReferencedByInline, ReferencedByParent,
|
Question, Recipe, Recommendation, Recommender, ReferencedByGenRel,
|
||||||
RelatedPrepopulated, Report, Reservation, Restaurant,
|
ReferencedByInline, ReferencedByParent, RelatedPrepopulated, Report,
|
||||||
RowLevelChangePermissionModel, Section, ShortMessage, Simple, Sketch,
|
Reservation, Restaurant, RowLevelChangePermissionModel, Section,
|
||||||
State, Story, StumpJoke, Subscriber, SuperVillain, Telegram, Thing,
|
ShortMessage, Simple, Sketch, State, Story, StumpJoke, Subscriber,
|
||||||
Topping, UnchangeableObject, UndeletableObject, UnorderedObject,
|
SuperVillain, Telegram, Thing, Topping, UnchangeableObject,
|
||||||
UserMessenger, Villain, Vodcast, Whatsit, Widget, Worker, WorkHour,
|
UndeletableObject, UnorderedObject, UserMessenger, Villain, Vodcast,
|
||||||
|
Whatsit, Widget, Worker, WorkHour,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -944,6 +945,8 @@ site.register(ReferencedByParent)
|
||||||
site.register(ChildOfReferer)
|
site.register(ChildOfReferer)
|
||||||
site.register(ReferencedByInline)
|
site.register(ReferencedByInline)
|
||||||
site.register(InlineReferer, InlineRefererAdmin)
|
site.register(InlineReferer, InlineRefererAdmin)
|
||||||
|
site.register(ReferencedByGenRel)
|
||||||
|
site.register(GenRelReference)
|
||||||
|
|
||||||
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
||||||
# That way we cover all four cases:
|
# That way we cover all four cases:
|
||||||
|
|
|
@ -938,3 +938,14 @@ class ExplicitlyProvidedPK(models.Model):
|
||||||
|
|
||||||
class ImplicitlyGeneratedPK(models.Model):
|
class ImplicitlyGeneratedPK(models.Model):
|
||||||
name = models.IntegerField(unique=True)
|
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)
|
||||||
|
|
|
@ -725,6 +725,14 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
||||||
response = self.client.get(reverse('admin:admin_views_referencedbyinline_changelist'), {TO_FIELD_VAR: 'name'})
|
response = self.client.get(reverse('admin:admin_views_referencedbyinline_changelist'), {TO_FIELD_VAR: 'name'})
|
||||||
self.assertEqual(response.status_code, 200)
|
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
|
# We also want to prevent the add, change, and delete views from
|
||||||
# leaking a disallowed field value.
|
# leaking a disallowed field value.
|
||||||
with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls:
|
with patch_logger('django.security.DisallowedModelAdminToField', 'error') as calls:
|
||||||
|
|
Loading…
Reference in New Issue