1
0
mirror of https://github.com/django/django.git synced 2025-04-17 22:04:38 +00:00

[1.9.x] Fixed -- Accounted for generic relations in the admin to field validation

Thanks to Jonathan Liuti for the report and Tim Graham for the review.

Backport of 9dcfecb7c6c8285630ad271888a9ec4ba9140e3a from master
This commit is contained in:
Simon Charette 2015-10-28 11:25:25 -04:00
parent 6bb9f51ab8
commit 6eaf43a244
5 changed files with 40 additions and 13 deletions
django/contrib/admin
docs/releases
tests/admin_views

@ -413,8 +413,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.remote_field
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 False

@ -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`).

@ -31,18 +31,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,
)
@ -944,6 +945,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:

@ -938,3 +938,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)

@ -725,6 +725,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: