Fixed #20883 -- Made model inheritance find parent links in abstract parents
This commit is contained in:
parent
dcdc579d16
commit
163a34ce4b
|
@ -184,10 +184,21 @@ class ModelBase(type):
|
||||||
else:
|
else:
|
||||||
new_class._meta.concrete_model = new_class
|
new_class._meta.concrete_model = new_class
|
||||||
|
|
||||||
# Do the appropriate setup for any model parents.
|
# Collect the parent links for multi-table inheritance.
|
||||||
o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
|
parent_links = {}
|
||||||
if isinstance(f, OneToOneField)])
|
for base in reversed([new_class] + parents):
|
||||||
|
# Conceptually equivalent to `if base is Model`.
|
||||||
|
if not hasattr(base, '_meta'):
|
||||||
|
continue
|
||||||
|
# Skip concrete parent classes.
|
||||||
|
if base != new_class and not base._meta.abstract:
|
||||||
|
continue
|
||||||
|
# Locate OneToOneField instances.
|
||||||
|
for field in base._meta.local_fields:
|
||||||
|
if isinstance(field, OneToOneField):
|
||||||
|
parent_links[field.rel.to] = field
|
||||||
|
|
||||||
|
# Do the appropriate setup for any model parents.
|
||||||
for base in parents:
|
for base in parents:
|
||||||
original_base = base
|
original_base = base
|
||||||
if not hasattr(base, '_meta'):
|
if not hasattr(base, '_meta'):
|
||||||
|
@ -208,8 +219,8 @@ class ModelBase(type):
|
||||||
if not base._meta.abstract:
|
if not base._meta.abstract:
|
||||||
# Concrete classes...
|
# Concrete classes...
|
||||||
base = base._meta.concrete_model
|
base = base._meta.concrete_model
|
||||||
if base in o2o_map:
|
if base in parent_links:
|
||||||
field = o2o_map[base]
|
field = parent_links[base]
|
||||||
elif not is_proxy:
|
elif not is_proxy:
|
||||||
attr_name = '%s_ptr' % base._meta.model_name
|
attr_name = '%s_ptr' % base._meta.model_name
|
||||||
field = OneToOneField(base, name=attr_name,
|
field = OneToOneField(base, name=attr_name,
|
||||||
|
|
|
@ -142,6 +142,9 @@ Minor features
|
||||||
the file system permissions of directories created during file upload, like
|
the file system permissions of directories created during file upload, like
|
||||||
:setting:`FILE_UPLOAD_PERMISSIONS` does for the files themselves.
|
:setting:`FILE_UPLOAD_PERMISSIONS` does for the files themselves.
|
||||||
|
|
||||||
|
* Explicit :class:`~django.db.models.OneToOneField` for
|
||||||
|
:ref:`multi-table-inheritance` are now discovered in abstract classes.
|
||||||
|
|
||||||
Backwards incompatible changes in 1.7
|
Backwards incompatible changes in 1.7
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,19 @@ class ParkingLot3(Place):
|
||||||
primary_key = models.AutoField(primary_key=True)
|
primary_key = models.AutoField(primary_key=True)
|
||||||
parent = models.OneToOneField(Place, parent_link=True)
|
parent = models.OneToOneField(Place, parent_link=True)
|
||||||
|
|
||||||
|
class ParkingLot4(models.Model):
|
||||||
|
# Test parent_link connector can be discovered in abstract classes.
|
||||||
|
parent = models.OneToOneField(Place, parent_link=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
class ParkingLot4A(ParkingLot4, Place):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ParkingLot4B(Place, ParkingLot4):
|
||||||
|
pass
|
||||||
|
|
||||||
class Supplier(models.Model):
|
class Supplier(models.Model):
|
||||||
restaurant = models.ForeignKey(Restaurant)
|
restaurant = models.ForeignKey(Restaurant)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@ from .models import (Place, Restaurant, ItalianRestaurant, ParkingLot,
|
||||||
ParkingLot2, ParkingLot3, Supplier, Wholesaler, Child, SelfRefParent,
|
ParkingLot2, ParkingLot3, Supplier, Wholesaler, Child, SelfRefParent,
|
||||||
SelfRefChild, ArticleWithAuthor, M2MChild, QualityControl, DerivedM,
|
SelfRefChild, ArticleWithAuthor, M2MChild, QualityControl, DerivedM,
|
||||||
Person, BirthdayParty, BachelorParty, MessyBachelorParty,
|
Person, BirthdayParty, BachelorParty, MessyBachelorParty,
|
||||||
InternalCertificationAudit, BusStation, TrainStation, User, Profile)
|
InternalCertificationAudit, BusStation, TrainStation, User, Profile,
|
||||||
|
ParkingLot4A, ParkingLot4B)
|
||||||
|
|
||||||
|
|
||||||
class ModelInheritanceTest(TestCase):
|
class ModelInheritanceTest(TestCase):
|
||||||
|
@ -311,6 +312,19 @@ class ModelInheritanceTest(TestCase):
|
||||||
ParkingLot3._meta.get_ancestor_link(Place).name,
|
ParkingLot3._meta.get_ancestor_link(Place).name,
|
||||||
"parent")
|
"parent")
|
||||||
|
|
||||||
|
def test_use_explicit_o2o_to_parent_from_abstract_model(self):
|
||||||
|
self.assertEqual(ParkingLot4A._meta.pk.name, "parent")
|
||||||
|
ParkingLot4A.objects.create(
|
||||||
|
name="Parking4A",
|
||||||
|
address='21 Jump Street',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(ParkingLot4B._meta.pk.name, "parent")
|
||||||
|
ParkingLot4A.objects.create(
|
||||||
|
name="Parking4B",
|
||||||
|
address='21 Jump Street',
|
||||||
|
)
|
||||||
|
|
||||||
def test_all_fields_from_abstract_base_class(self):
|
def test_all_fields_from_abstract_base_class(self):
|
||||||
"""
|
"""
|
||||||
Regression tests for #7588
|
Regression tests for #7588
|
||||||
|
|
Loading…
Reference in New Issue