mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Co-authored-by: Jarek Glowacki <jarekwg@gmail.com>
This commit is contained in:
@@ -34,7 +34,12 @@ class AbstractInheritanceTests(SimpleTestCase):
|
||||
self.assertEqual(DerivedChild._meta.get_field('name').max_length, 50)
|
||||
self.assertEqual(DerivedGrandChild._meta.get_field('name').max_length, 50)
|
||||
|
||||
def test_multiple_inheritance_cannot_shadow_inherited_field(self):
|
||||
def test_multiple_inheritance_allows_inherited_field(self):
|
||||
"""
|
||||
Single layer multiple inheritance is as expected, deriving the
|
||||
inherited field from the first base.
|
||||
"""
|
||||
|
||||
class ParentA(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
@@ -50,14 +55,46 @@ class AbstractInheritanceTests(SimpleTestCase):
|
||||
class Child(ParentA, ParentB):
|
||||
pass
|
||||
|
||||
self.assertEqual(Child.check(), [
|
||||
Error(
|
||||
"The field 'name' clashes with the field 'name' from model "
|
||||
"'model_inheritance.child'.",
|
||||
obj=Child._meta.get_field('name'),
|
||||
id='models.E006',
|
||||
),
|
||||
])
|
||||
self.assertEqual(Child.check(), [])
|
||||
inherited_field = Child._meta.get_field('name')
|
||||
self.assertTrue(isinstance(inherited_field, models.CharField))
|
||||
self.assertEqual(inherited_field.max_length, 255)
|
||||
|
||||
def test_diamond_shaped_multiple_inheritance_is_depth_first(self):
|
||||
"""
|
||||
In contrast to standard Python MRO, resolution of inherited fields is
|
||||
strictly depth-first, rather than breadth-first in diamond-shaped cases.
|
||||
|
||||
This is because a copy of the parent field descriptor is placed onto
|
||||
the model class in ModelBase.__new__(), rather than the attribute
|
||||
lookup going via bases. (It only **looks** like inheritance.)
|
||||
|
||||
Here, Child inherits name from Root, rather than ParentB.
|
||||
"""
|
||||
|
||||
class Root(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
class ParentA(Root):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
class ParentB(Root):
|
||||
name = models.IntegerField()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
class Child(ParentA, ParentB):
|
||||
pass
|
||||
|
||||
self.assertEqual(Child.check(), [])
|
||||
inherited_field = Child._meta.get_field('name')
|
||||
self.assertTrue(isinstance(inherited_field, models.CharField))
|
||||
self.assertEqual(inherited_field.max_length, 255)
|
||||
|
||||
def test_target_field_may_be_pushed_down(self):
|
||||
"""
|
||||
|
||||
@@ -2,6 +2,7 @@ from operator import attrgetter
|
||||
|
||||
from django.core.exceptions import FieldError, ValidationError
|
||||
from django.db import connection, models
|
||||
from django.db.models.query_utils import DeferredAttribute
|
||||
from django.test import SimpleTestCase, TestCase
|
||||
from django.test.utils import CaptureQueriesContext, isolate_apps
|
||||
|
||||
@@ -222,6 +223,36 @@ class ModelInheritanceTests(TestCase):
|
||||
self.assertIs(models.QuerySet[Post, Post], models.QuerySet)
|
||||
self.assertIs(models.QuerySet[Post, int, str], models.QuerySet)
|
||||
|
||||
def test_shadow_parent_attribute_with_field(self):
|
||||
class ScalarParent(models.Model):
|
||||
foo = 1
|
||||
|
||||
class ScalarOverride(ScalarParent):
|
||||
foo = models.IntegerField()
|
||||
|
||||
self.assertEqual(type(ScalarOverride.foo), DeferredAttribute)
|
||||
|
||||
def test_shadow_parent_property_with_field(self):
|
||||
class PropertyParent(models.Model):
|
||||
@property
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class PropertyOverride(PropertyParent):
|
||||
foo = models.IntegerField()
|
||||
|
||||
self.assertEqual(type(PropertyOverride.foo), DeferredAttribute)
|
||||
|
||||
def test_shadow_parent_method_with_field(self):
|
||||
class MethodParent(models.Model):
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
class MethodOverride(MethodParent):
|
||||
foo = models.IntegerField()
|
||||
|
||||
self.assertEqual(type(MethodOverride.foo), DeferredAttribute)
|
||||
|
||||
|
||||
class ModelInheritanceDataTests(TestCase):
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user