From 84e91262d6b94d35b381d0a46ff5402eaac7c996 Mon Sep 17 00:00:00 2001 From: Ahmed Nassar Date: Sun, 20 Apr 2025 11:57:40 +0200 Subject: [PATCH] Fixed #36295, Refs #24305 -- Allowed overriding GenericForeignKey fields on abstract models. --- AUTHORS | 1 + django/db/models/base.py | 7 +++-- .../test_abstract_inheritance.py | 26 +++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 792a0916d1..89626872ab 100644 --- a/AUTHORS +++ b/AUTHORS @@ -34,6 +34,7 @@ answer newbie questions, and generally made Django that much better: Ahmad Alhashemi Ahmad Al-Ibrahim Ahmed Eltawela + Ahmed Nassar ajs Akash Agrawal Akash Kumar Sen diff --git a/django/db/models/base.py b/django/db/models/base.py index 51aadd935b..34c537fea0 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -348,7 +348,7 @@ class ModelBase(type): new_class._meta.parents.update(base_parents) # Inherit private fields (like GenericForeignKey) from the parent - # class + # class if they are not overridden. for field in base._meta.private_fields: if field.name in field_names: if not base._meta.abstract: @@ -361,7 +361,10 @@ class ModelBase(type): base.__name__, ) ) - else: + elif ( + field.name not in new_class.__dict__ + and field.name not in inherited_attributes + ): field = copy.deepcopy(field) if not base._meta.abstract: field.mti_inherited = True diff --git a/tests/model_inheritance/test_abstract_inheritance.py b/tests/model_inheritance/test_abstract_inheritance.py index 24362292a1..9b9da437da 100644 --- a/tests/model_inheritance/test_abstract_inheritance.py +++ b/tests/model_inheritance/test_abstract_inheritance.py @@ -184,6 +184,32 @@ class AbstractInheritanceTests(SimpleTestCase): ExtendModelAbstract._meta.get_field("field"), GenericRelation ) + def test_override_private_field_with_attr(self): + class AbstractBase(models.Model): + content_type = models.ForeignKey( + ContentType, on_delete=models.SET_NULL, null=True, blank=True + ) + object_id = models.PositiveIntegerField(null=True, blank=True) + related_object = GenericForeignKey("content_type", "object_id") + + class Meta: + abstract = True + + class Descendant(AbstractBase): + related_object = None + + class Mixin: + related_object = None + + class MultiDescendant(Mixin, AbstractBase): + pass + + with self.assertRaises(FieldDoesNotExist): + Descendant._meta.get_field("related_object") + + with self.assertRaises(FieldDoesNotExist): + MultiDescendant._meta.get_field("related_object") + def test_cannot_override_indirect_abstract_field(self): class AbstractBase(models.Model): name = models.CharField(max_length=30)