Loading django/db/models/options.py +7 −7 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ from django.db.models.fields.related import ManyToManyField from django.db.models.fields import AutoField from django.db.models.fields.proxy import OrderWrt 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.encoding import force_text, smart_text, python_2_unicode_compatible from django.utils.functional import cached_property Loading Loading @@ -634,14 +634,14 @@ class Options(object): def get_parent_list(self): """ Returns a list of all the ancestor of this model as a list. Useful for determining if something is an ancestor, regardless of lineage. Returns all the ancestors of this model as a list ordered by MRO. Useful for determining if something is an ancestor, regardless of lineage. """ result = set() result = OrderedSet(self.parents) for parent in self.parents: result.add(parent) result.update(parent._meta.get_parent_list()) return result for ancestor in parent._meta.get_parent_list(): result.add(ancestor) return list(result) def get_ancestor_link(self, ancestor): """ Loading tests/model_meta/models.py +17 −0 Original line number Diff line number Diff line Loading @@ -118,3 +118,20 @@ class Relating(models.Model): # ManyToManyField to Person people = models.ManyToManyField(Person, related_name='relating_people') 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 tests/model_meta/tests.py +12 −1 Original line number Diff line number Diff line Loading @@ -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.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 Loading Loading @@ -245,3 +248,11 @@ class RelationTreeTests(TestCase): ]) ) 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]) Loading
django/db/models/options.py +7 −7 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ from django.db.models.fields.related import ManyToManyField from django.db.models.fields import AutoField from django.db.models.fields.proxy import OrderWrt 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.encoding import force_text, smart_text, python_2_unicode_compatible from django.utils.functional import cached_property Loading Loading @@ -634,14 +634,14 @@ class Options(object): def get_parent_list(self): """ Returns a list of all the ancestor of this model as a list. Useful for determining if something is an ancestor, regardless of lineage. Returns all the ancestors of this model as a list ordered by MRO. Useful for determining if something is an ancestor, regardless of lineage. """ result = set() result = OrderedSet(self.parents) for parent in self.parents: result.add(parent) result.update(parent._meta.get_parent_list()) return result for ancestor in parent._meta.get_parent_list(): result.add(ancestor) return list(result) def get_ancestor_link(self, ancestor): """ Loading
tests/model_meta/models.py +17 −0 Original line number Diff line number Diff line Loading @@ -118,3 +118,20 @@ class Relating(models.Model): # ManyToManyField to Person people = models.ManyToManyField(Person, related_name='relating_people') 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
tests/model_meta/tests.py +12 −1 Original line number Diff line number Diff line Loading @@ -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.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 Loading Loading @@ -245,3 +248,11 @@ class RelationTreeTests(TestCase): ]) ) 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])