[1.8.x] Fixed #24266 -- Changed get_parent_list to return a list ordered by MRO.

Thanks to Aron Podrigal for the initial patch and Tim for the review.

Backport of 65e005f8cd from master
This commit is contained in:
Simon Charette 2015-02-03 15:13:43 -05:00
parent dd83bab931
commit cbcf92e95f
3 changed files with 36 additions and 8 deletions

View File

@ -12,7 +12,7 @@ from django.db.models.fields.related import ManyToManyField
from django.db.models.fields import AutoField from django.db.models.fields import AutoField
from django.db.models.fields.proxy import OrderWrt from django.db.models.fields.proxy import OrderWrt
from django.utils import six from django.utils import six
from django.utils.datastructures import ImmutableList from django.utils.datastructures import ImmutableList, OrderedSet
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible
from django.utils.functional import cached_property from django.utils.functional import cached_property
@ -634,14 +634,14 @@ class Options(object):
def get_parent_list(self): def get_parent_list(self):
""" """
Returns a list of all the ancestor of this model as a list. Useful for Returns all the ancestors of this model as a list ordered by MRO.
determining if something is an ancestor, regardless of lineage. Useful for determining if something is an ancestor, regardless of lineage.
""" """
result = set() result = OrderedSet(self.parents)
for parent in self.parents: for parent in self.parents:
result.add(parent) for ancestor in parent._meta.get_parent_list():
result.update(parent._meta.get_parent_list()) result.add(ancestor)
return result return list(result)
def get_ancestor_link(self, ancestor): def get_ancestor_link(self, ancestor):
""" """

View File

@ -118,3 +118,20 @@ class Relating(models.Model):
# ManyToManyField to Person # ManyToManyField to Person
people = models.ManyToManyField(Person, related_name='relating_people') people = models.ManyToManyField(Person, related_name='relating_people')
people_hidden = models.ManyToManyField(Person, related_name='+') people_hidden = models.ManyToManyField(Person, related_name='+')
# ParentListTests models
class CommonAncestor(models.Model):
pass
class FirstParent(CommonAncestor):
first_ancestor = models.OneToOneField(CommonAncestor, primary_key=True, parent_link=True)
class SecondParent(CommonAncestor):
second_ancestor = models.OneToOneField(CommonAncestor, primary_key=True, parent_link=True)
class Child(FirstParent, SecondParent):
pass

View File

@ -5,7 +5,10 @@ from django.db.models.fields import related, CharField, Field
from django.db.models.options import IMMUTABLE_WARNING, EMPTY_RELATION_TREE from django.db.models.options import IMMUTABLE_WARNING, EMPTY_RELATION_TREE
from django.test import TestCase from django.test import TestCase
from .models import Relation, AbstractPerson, BasePerson, Person, ProxyPerson, Relating from .models import (
Relation, AbstractPerson, BasePerson, Person, ProxyPerson, Relating,
CommonAncestor, FirstParent, SecondParent, Child
)
from .results import TEST_RESULTS from .results import TEST_RESULTS
@ -245,3 +248,11 @@ class RelationTreeTests(TestCase):
]) ])
) )
self.assertEqual([field.related_query_name() for field in AbstractPerson._meta._relation_tree], []) self.assertEqual([field.related_query_name() for field in AbstractPerson._meta._relation_tree], [])
class ParentListTests(TestCase):
def test_get_parent_list(self):
self.assertEqual(CommonAncestor._meta.get_parent_list(), [])
self.assertEqual(FirstParent._meta.get_parent_list(), [CommonAncestor])
self.assertEqual(SecondParent._meta.get_parent_list(), [CommonAncestor])
self.assertEqual(Child._meta.get_parent_list(), [FirstParent, SecondParent, CommonAncestor])