Code

Ticket #17270: manager.2.py

File manager.2.py, 3.5 KB (added by Wojciech Banaś <fizista@…>, 2 years ago)

Improved and simplified version.

Line 
1from types import MethodType
2from django.db import models
3from django.db.models.query import QuerySet
4from django.db.models.query import EmptyQuerySet
5
6class ManagerQuerySetDecorator(models.Manager):
7    """
8    Extends the operation methods of the manager on subqueries QuerySet objects.
9   
10    The "standard manager" you can only like this:
11    SomeModel.object.some_method_manager().all().filter(...). ...
12   
13    But this does not work:
14    SomeModel.object.all().some_method_manager()
15   
16    And this it works with the use of this class / patches:
17    SomeModel.object.all().some_method_manager().filter(...).some_method_manager2(). ...
18    SomeModel.object.some_method_manager().some_method_manager2().some_method_manager3(). ...
19   
20    Extension of the methods manager on all child objects "QuerySeth".
21   
22    Example:
23   
24    class Animals(models.Model):
25        type = models.CharField('Type of animal') # dog, cat, elephant
26        color = models.CharField('Colour Name')
27       
28        objects = AnimalsManager()
29       
30    class AnimalsManager(ManagerQuerySetDecorator):
31   
32        def get_dogs(self):
33            return self.get_query_set().filter(type='dog')
34        get_dogs.queryset_method = True
35       
36        def get_cats(self):
37            return self.get_query_set().filter(type='cat')
38        get_cats.queryset_method = True
39       
40        def get_white_animals(self):
41            return self.get_query_set().filter(color='white')
42        get_white_animals.queryset_method = True
43       
44        def get_black_animals(self):
45            return self.get_query_set().filter(color='black')
46        get_black_animals.queryset_method = True
47       
48        def get_brown_animals(self):
49            return self.get_query_set().filter(color='black')
50
51       
52    Animals(type='dog', color='black').save()
53    Animals(type='dog', color='bown').save()
54    Animals(type='dog', color='white').save()
55    Animals(type='cat', color='black').save()
56    Animals(type='cat', color='bown').save()
57    Animals(type='cat', color='white').save()
58   
59    animals = Animals.objects.get_black_animals().get_dogs()
60    # return list black dogs
61
62    animals = Animals.objects.get_white_animals().get_cats()
63    # return list white cats
64   
65    # When ffff equals False, or not defined (as it is in
66    # the original model manager), we can not perform such an operation:
67    animals = Animals.objects.get_cats().get_brown_animals()
68    # return:
69    # AttributeError: 'QuerySet' object has no attribute 'get_brown_animals'
70   
71    # but:
72    animals = Animals.objects.get_brown_animals().get_cats()
73    # return brown cats, because get_cat() present in all parent object instances.
74    """
75   
76    def _get_queryset_class(self):
77        class ManagerQuerySet(QuerySet):
78            def none(self):
79                """
80                Returns an empty QuerySet.
81                """
82                klass = type( 
83                             "_InstrumentedEmptyQuerySet_%s" % self.__class__.__name__, 
84                             (EmptyQuerySet, self.__class__), {}) 
85                return self._clone(klass=klass)
86        for attrib_name in dir(self):
87            attrib = getattr(self,attrib_name)
88            if isinstance(attrib, MethodType) and hasattr(attrib, 'queryset_method') and  attrib.queryset_method:
89                setattr(ManagerQuerySet, attrib_name, attrib)
90        return ManagerQuerySet
91   
92    def get_query_set(self):
93        return self._get_queryset_class()(self.model, using=self._db)
94   
95