Fixed #20883 -- Made model inheritance find parent links in abstract parents

This commit is contained in:
Loic Bistuer 2013-08-12 18:30:38 +07:00 committed by Anssi Kääriäinen
parent dcdc579d16
commit 163a34ce4b
4 changed files with 47 additions and 6 deletions

View File

@ -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,

View File

@ -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
===================================== =====================================

View File

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

View File

@ -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