Ticket #17270: manager_queryset.diff

File manager_queryset.diff, 5.9 KB (added by Wojciech Banaś <fizista@…>, 3 years ago)

Another solution, tested, working, downwards compatible, django devel path

  • django/db/models/manager.py

     
    4646    # Tracks each time a Manager instance is created. Used to retain order.
    4747    creation_counter = 0
    4848
    49     def __init__(self):
     49    def __init__(self, queryset_cls=None, queryset_method_names=[]):
    5050        super(Manager, self).__init__()
    5151        self._set_creation_counter()
    5252        self.model = None
    5353        self._inherited = False
    5454        self._db = None
     55        self._queryset_cls = queryset_cls or QuerySet
     56        self.implement_queryset_methods(*queryset_method_names)
    5557
     58    def implement_queryset_cls(self, cls):
     59        self._queryset_cls = cls
     60
     61    def implement_queryset_methods(self, *method_names):
     62        for method_name in method_names:
     63            self.implement_queryset_method(method_name)
     64
     65    def implement_queryset_method(self, name):
     66        def queryset_method_deco(*args, **kwarg):
     67            return getattr(self.get_query_set(), name)(*args, **kwarg)
     68        setattr(self, name, queryset_method_deco)
     69       
    5670    def contribute_to_class(self, model, name):
    5771        # TODO: Use weakref because of possible memory leak / circular reference.
    5872        self.model = model
     
    101115    #######################
    102116
    103117    def get_empty_query_set(self):
    104         return EmptyQuerySet(self.model, using=self._db)
     118        return self._queryset_cls(self.model, using=self._db).none()
    105119
    106120    def get_query_set(self):
    107121        """Returns a new QuerySet object.  Subclasses can override this method
    108122        to easily customize the behavior of the Manager.
    109123        """
    110         return QuerySet(self.model, using=self._db)
     124        return self._queryset_cls(self.model, using=self._db)
    111125
    112126    def none(self):
    113127        return self.get_empty_query_set()
  • tests/modeltests/custom_managers/tests.py

     
    11from __future__ import absolute_import
    22
     3import pickle,tempfile
     4
    35from django.test import TestCase
    46
    57from .models import Person, Book, Car, PersonManager, PublishedBookManager
     
    911    def test_manager(self):
    1012        p1 = Person.objects.create(first_name="Bugs", last_name="Bunny", fun=True)
    1113        p2 = Person.objects.create(first_name="Droopy", last_name="Dog", fun=False)
     14        p3 = Person.objects.create(first_name="Elmer", last_name="Fudd", fun=False)
    1215
    13         self.assertQuerysetEqual(
    14             Person.objects.get_fun_people(), [
    15                 "Bugs Bunny"
    16             ],
    17             unicode
    18         )
     16        for objects in [Person.objects, Person.objects_second, Person.objects_third]:
     17            self.assertQuerysetEqual(
     18                objects.get_fun_people(), [
     19                    "Bugs Bunny"
     20                ],
     21                unicode
     22            )
     23           
     24            self.assertQuerysetEqual(
     25                objects.all().get_fun_people(), [
     26                    "Bugs Bunny"
     27                ],
     28                unicode
     29            )
     30           
     31            self.assertQuerysetEqual(
     32                objects.get_fun_people().get_not_fun_people(), [],
     33                unicode
     34            )
     35   
     36            self.assertQuerysetEqual(
     37                objects.filter(id__in=(p1.id,p2.id)).get_fun_people(), [
     38                    "Bugs Bunny"
     39                ],
     40                unicode
     41            )
     42           
     43            self.assertRaises(AttributeError, lambda: objects.all().get_fun_people_manager)
     44           
     45            # Test dump object
     46            f = tempfile.TemporaryFile(mode='wb')
     47            try:
     48                pickle.dump(objects.all().get_fun_people(), f, pickle.HIGHEST_PROTOCOL)
     49            finally:
     50                f.close()
     51       
    1952        # The RelatedManager used on the 'books' descriptor extends the default
    2053        # manager
    2154        self.assertTrue(isinstance(p2.books, PublishedBookManager))
  • tests/modeltests/custom_managers/models.py

     
    1313
    1414# An example of a custom manager called "objects".
    1515
    16 class PersonManager(models.Manager):
     16class ManagerQuerySetFirstPart(models.query.QuerySet):
    1717    def get_fun_people(self):
    1818        return self.filter(fun=True)
     19   
     20class ManagerQuerySetSecondPart(models.query.QuerySet):
     21    def get_not_fun_people(self):
     22        return self.filter(fun=False)
    1923
     24class ManagerQuerySetMaster(ManagerQuerySetFirstPart, ManagerQuerySetSecondPart):
     25    pass
     26
     27class ManagerQuerySet(models.query.QuerySet):
     28    def get_fun_people(self):
     29        return self.filter(fun=True)
     30   
     31    def get_not_fun_people(self):
     32        return self.filter(fun=False)
     33   
     34class PersonManager(models.Manager):
     35    def __init__(self):
     36        super(PersonManager, self).__init__()
     37        self.implement_queryset_cls(ManagerQuerySet)
     38        self.implement_queryset_methods('get_fun_people', 'get_not_fun_people')
     39       
     40    def get_fun_people_manager(self):
     41        return self.filter(fun=True)
     42   
     43class PersonManagerSecond(models.Manager):
     44    def get_fun_people_manager(self):
     45        return self.filter(fun=True)
     46
    2047class Person(models.Model):
    2148    first_name = models.CharField(max_length=30)
    2249    last_name = models.CharField(max_length=30)
    2350    fun = models.BooleanField()
    2451    objects = PersonManager()
    25 
     52    objects_second = PersonManagerSecond(ManagerQuerySet, ['get_fun_people', 'get_not_fun_people'])
     53    objects_third = PersonManagerSecond(ManagerQuerySetMaster, ['get_fun_people', 'get_not_fun_people'])
     54   
    2655    def __unicode__(self):
    2756        return u"%s %s" % (self.first_name, self.last_name)
    2857
Back to Top