Code

Ticket #17270: manager.4.py

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

Dynamic class is created only once

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    def __init__(self):
76        super(ManagerQuerySetDecorator, self).__init__()
77        self._query_set_class = self._get_queryset_class()
78
79    def _get_queryset_class(self):
80        class ManagerQuerySet(QuerySet):
81            def none(self):
82                """
83                Returns an empty QuerySet.
84                """
85                klass = type( 
86                             "_InstrumentedEmptyQuerySet_%s" % self.__class__.__name__, 
87                             (EmptyQuerySet, self.__class__), {}) 
88                return self._clone(klass=klass)
89        for attrib_name in dir(self):
90            attrib = self.__getattribute__(attrib_name)
91            if isinstance(attrib, MethodType) and hasattr(attrib, 'queryset_method') and  attrib.queryset_method:
92                setattr(ManagerQuerySet, attrib_name, attrib)
93        return ManagerQuerySet
94   
95    def get_query_set(self):
96        return self._query_set_class(self.model, using=self._db)
97   
98