Skip to content

Commit

Permalink
Merge pull request #534 from sephii/fix-multiple-managers
Browse files Browse the repository at this point in the history
Use default tree manager when multiple tree managers are defined
  • Loading branch information
craigds committed Feb 7, 2017
2 parents f5f75c3 + fa4221c commit 10783b8
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
27 changes: 16 additions & 11 deletions mptt/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,18 +338,23 @@ def register(meta, cls, **kwargs):
if not abstract:
# make sure we have a tree manager somewhere
tree_manager = None
if hasattr(cls._meta, 'concrete_managers'): # Django < 1.10
cls_managers = cls._meta.concrete_managers + cls._meta.abstract_managers
cls_managers = [r[2] for r in cls_managers]
# Use the default manager defined on the class if any
if cls._default_manager and isinstance(cls._default_manager, TreeManager):
tree_manager = cls._default_manager
else:
cls_managers = cls._meta.managers

for cls_manager in cls_managers:
if isinstance(cls_manager, TreeManager):
# prefer any locally defined manager (i.e. keep going if not local)
if cls_manager.model is cls:
tree_manager = cls_manager
break
if hasattr(cls._meta, 'concrete_managers'): # Django < 1.10
# Django < 1.10 doesn't sort managers
cls_managers = sorted(cls._meta.concrete_managers + cls._meta.abstract_managers)
cls_managers = [r[2] for r in cls_managers]
else:
cls_managers = cls._meta.managers

for cls_manager in cls_managers:
if isinstance(cls_manager, TreeManager):
# prefer any locally defined manager (i.e. keep going if not local)
if cls_manager.model is cls:
tree_manager = cls_manager
break

if tree_manager and tree_manager.model is not cls:
tree_manager = tree_manager._copy_to_model(cls)
Expand Down
16 changes: 16 additions & 0 deletions tests/myapp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,22 @@ class SwappedInModel(MPTTModel):
name = models.CharField(max_length=50)


# Default manager
class MultipleManager(TreeManager):
def get_queryset(self):
return super(MultipleManager, self).get_queryset().exclude(published=False)


class MultipleManagerModel(MPTTModel):
parent = TreeForeignKey(
'self', null=True, blank=True, related_name='children',
on_delete=models.CASCADE)
published = models.BooleanField()

objects = TreeManager()
foo_objects = MultipleManager()


class AutoNowDateFieldModel(MPTTModel):
parent = TreeForeignKey(
'self', null=True, blank=True, related_name='children',
Expand Down
9 changes: 8 additions & 1 deletion tests/myapp/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
Category, Item, Genre, CustomPKName, SingleProxyModel, DoubleProxyModel,
ConcreteModel, OrderedInsertion, AutoNowDateFieldModel, Person,
CustomTreeQueryset, Node, ReferencingModel, CustomTreeManager, Book,
UUIDNode, Student)
UUIDNode, Student, MultipleManagerModel)


def get_tree_details(nodes):
Expand Down Expand Up @@ -1299,6 +1299,13 @@ def test_num_queries_on_get_queryset_descendants(self):
Category.objects.all(), include_self=True)
self.assertEqual(len(qs), 10)

def test_default_manager_with_multiple_managers(self):
"""
Test that a model with multiple managers defined always uses the
default manager as the tree manager.
"""
self.assertEqual(type(MultipleManagerModel._tree_manager), TreeManager)


class CacheTreeChildrenTestCase(TreeTestCase):

Expand Down

0 comments on commit 10783b8

Please sign in to comment.