mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	[1.9.x] 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.
Backport of 9dcfecb7c6 from master
			
			
This commit is contained in:
		| @@ -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: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user