Skip to content

Commit

Permalink
POC to address concerns about manager-only methods. Refs https://code…
Browse files Browse the repository at this point in the history
  • Loading branch information
loic committed Jul 3, 2013
1 parent ed72280 commit 2e129ae
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 6 deletions.
6 changes: 3 additions & 3 deletions django/db/models/manager.py
Expand Up @@ -58,7 +58,7 @@ class RenameManagerMethods(RenameMethodsBase):
class _Manager(six.with_metaclass(RenameManagerMethods)):
# Tracks each time a Manager instance is created. Used to retain order.
creation_counter = 0
queryset_class = QuerySet
_queryset_class = QuerySet

def __init__(self):
super(_Manager, self).__init__()
Expand Down Expand Up @@ -121,7 +121,7 @@ def get_queryset(self):
"""Returns a new QuerySet object. Subclasses can override this method
to easily customize the behavior of the Manager.
"""
return self.queryset_class(self.model, using=self._db)
return self._queryset_class(self.model, using=self._db)

def all(self):
# All can't be proxied to QuerySet, as prefetch_related is lost on
Expand All @@ -134,7 +134,7 @@ def _insert(self, objs, fields, **kwargs):
def raw(self, raw_query, params=None, *args, **kwargs):
return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs)

Manager = QuerySet.manager_cls(base_cls=_Manager)
Manager = QuerySet.get_manager_class(base_cls=_Manager)


class ManagerDescriptor(object):
Expand Down
11 changes: 8 additions & 3 deletions django/db/models/query.py
Expand Up @@ -30,6 +30,9 @@ class QuerySet(object):
"""
Represents a lazy database lookup for a set of objects.
"""

base_manager_class = None

def __init__(self, model=None, query=None, using=None):
self.model = model
self._db = using
Expand All @@ -42,7 +45,7 @@ def __init__(self, model=None, query=None, using=None):
self._known_related_objects = {} # {rel_field, {pk: rel_obj}}

@classmethod
def manager_cls(cls, base_cls=None):
def get_manager_class(cls, base_cls=None):
"""
Creates a manager class for this QuerySet class.
"""
Expand All @@ -56,18 +59,20 @@ def manager_copy(self, *args, **kwargs):
do_copy = getattr(maybe_copy, 'manager', None)
if do_copy or do_copy is None and not name.startswith('_'):
new_methods[name] = create_method(name)
if base_cls is None:
base_cls = cls.base_manager_class
if base_cls is None:
from django.db.models.manager import Manager as base_cls
manager_cls = type(
cls.__name__ + 'Manager',
(base_cls,),
new_methods)
manager_cls.queryset_class = cls
manager_cls._queryset_class = cls
return manager_cls

@classmethod
def as_manager(cls, base_cls=None):
manager_cls = cls.manager_cls(base_cls=base_cls)
manager_cls = cls.get_manager_class(base_cls)
return manager_cls()

########################
Expand Down
11 changes: 11 additions & 0 deletions tests/custom_managers/models.py
Expand Up @@ -35,13 +35,24 @@ def bar(self, *args, **kwargs):
return self.all()
bar.manager = True

class MyManager(models.Manager):
def manager_only(self):
pass

class MyQuerySet(models.QuerySet):
base_manager_class = MyManager

def manager_and_queryset_method(self):
pass

@python_2_unicode_compatible
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
fun = models.BooleanField()
objects = PersonManager()
other_objects = CustomQuerySet.as_manager(base_cls=PersonManager)
other_other_objects = MyQuerySet.as_manager()

def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
Expand Down
8 changes: 8 additions & 0 deletions tests/custom_managers/tests.py
Expand Up @@ -25,6 +25,14 @@ def test_manager(self):
)
print Person.other_objects.filter(fun=False)
print Person.other_objects.bar()

Person.other_other_objects.manager_and_queryset_method()
Person.other_other_objects.all().manager_and_queryset_method()

Person.other_other_objects.manager_only()
with self.assertRaises(AttributeError):
Person.other_other_objects.all().manager_only()

# The RelatedManager used on the 'books' descriptor extends the default
# manager
self.assertIsInstance(p2.books, PublishedBookManager)
Expand Down

0 comments on commit 2e129ae

Please sign in to comment.