Code

Ticket #17270: manager_queryset.diff

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

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

Line 
1Index: django/db/models/manager.py
2===================================================================
3--- django/db/models/manager.py (wersja 17163)
4+++ django/db/models/manager.py (kopia robocza)
5@@ -46,13 +46,27 @@
6     # Tracks each time a Manager instance is created. Used to retain order.
7     creation_counter = 0
8 
9-    def __init__(self):
10+    def __init__(self, queryset_cls=None, queryset_method_names=[]):
11         super(Manager, self).__init__()
12         self._set_creation_counter()
13         self.model = None
14         self._inherited = False
15         self._db = None
16+        self._queryset_cls = queryset_cls or QuerySet
17+        self.implement_queryset_methods(*queryset_method_names)
18 
19+    def implement_queryset_cls(self, cls):
20+        self._queryset_cls = cls
21+
22+    def implement_queryset_methods(self, *method_names):
23+        for method_name in method_names:
24+            self.implement_queryset_method(method_name)
25+
26+    def implement_queryset_method(self, name):
27+        def queryset_method_deco(*args, **kwarg):
28+            return getattr(self.get_query_set(), name)(*args, **kwarg)
29+        setattr(self, name, queryset_method_deco)
30+       
31     def contribute_to_class(self, model, name):
32         # TODO: Use weakref because of possible memory leak / circular reference.
33         self.model = model
34@@ -101,13 +115,13 @@
35     #######################
36 
37     def get_empty_query_set(self):
38-        return EmptyQuerySet(self.model, using=self._db)
39+        return self._queryset_cls(self.model, using=self._db).none()
40 
41     def get_query_set(self):
42         """Returns a new QuerySet object.  Subclasses can override this method
43         to easily customize the behavior of the Manager.
44         """
45-        return QuerySet(self.model, using=self._db)
46+        return self._queryset_cls(self.model, using=self._db)
47 
48     def none(self):
49         return self.get_empty_query_set()
50Index: tests/modeltests/custom_managers/tests.py
51===================================================================
52--- tests/modeltests/custom_managers/tests.py   (wersja 17163)
53+++ tests/modeltests/custom_managers/tests.py   (kopia robocza)
54@@ -1,5 +1,7 @@
55 from __future__ import absolute_import
56 
57+import pickle,tempfile
58+
59 from django.test import TestCase
60 
61 from .models import Person, Book, Car, PersonManager, PublishedBookManager
62@@ -9,13 +11,44 @@
63     def test_manager(self):
64         p1 = Person.objects.create(first_name="Bugs", last_name="Bunny", fun=True)
65         p2 = Person.objects.create(first_name="Droopy", last_name="Dog", fun=False)
66+        p3 = Person.objects.create(first_name="Elmer", last_name="Fudd", fun=False)
67 
68-        self.assertQuerysetEqual(
69-            Person.objects.get_fun_people(), [
70-                "Bugs Bunny"
71-            ],
72-            unicode
73-        )
74+        for objects in [Person.objects, Person.objects_second, Person.objects_third]:
75+            self.assertQuerysetEqual(
76+                objects.get_fun_people(), [
77+                    "Bugs Bunny"
78+                ],
79+                unicode
80+            )
81+           
82+            self.assertQuerysetEqual(
83+                objects.all().get_fun_people(), [
84+                    "Bugs Bunny"
85+                ],
86+                unicode
87+            )
88+           
89+            self.assertQuerysetEqual(
90+                objects.get_fun_people().get_not_fun_people(), [],
91+                unicode
92+            )
93+   
94+            self.assertQuerysetEqual(
95+                objects.filter(id__in=(p1.id,p2.id)).get_fun_people(), [
96+                    "Bugs Bunny"
97+                ],
98+                unicode
99+            )
100+           
101+            self.assertRaises(AttributeError, lambda: objects.all().get_fun_people_manager)
102+           
103+            # Test dump object
104+            f = tempfile.TemporaryFile(mode='wb')
105+            try:
106+                pickle.dump(objects.all().get_fun_people(), f, pickle.HIGHEST_PROTOCOL)
107+            finally:
108+                f.close()
109+       
110         # The RelatedManager used on the 'books' descriptor extends the default
111         # manager
112         self.assertTrue(isinstance(p2.books, PublishedBookManager))
113Index: tests/modeltests/custom_managers/models.py
114===================================================================
115--- tests/modeltests/custom_managers/models.py  (wersja 17163)
116+++ tests/modeltests/custom_managers/models.py  (kopia robocza)
117@@ -13,16 +13,45 @@
118 
119 # An example of a custom manager called "objects".
120 
121-class PersonManager(models.Manager):
122+class ManagerQuerySetFirstPart(models.query.QuerySet):
123     def get_fun_people(self):
124         return self.filter(fun=True)
125+   
126+class ManagerQuerySetSecondPart(models.query.QuerySet):
127+    def get_not_fun_people(self):
128+        return self.filter(fun=False)
129 
130+class ManagerQuerySetMaster(ManagerQuerySetFirstPart, ManagerQuerySetSecondPart):
131+    pass
132+
133+class ManagerQuerySet(models.query.QuerySet):
134+    def get_fun_people(self):
135+        return self.filter(fun=True)
136+   
137+    def get_not_fun_people(self):
138+        return self.filter(fun=False)
139+   
140+class PersonManager(models.Manager):
141+    def __init__(self):
142+        super(PersonManager, self).__init__()
143+        self.implement_queryset_cls(ManagerQuerySet)
144+        self.implement_queryset_methods('get_fun_people', 'get_not_fun_people')
145+       
146+    def get_fun_people_manager(self):
147+        return self.filter(fun=True)
148+   
149+class PersonManagerSecond(models.Manager):
150+    def get_fun_people_manager(self):
151+        return self.filter(fun=True)
152+
153 class Person(models.Model):
154     first_name = models.CharField(max_length=30)
155     last_name = models.CharField(max_length=30)
156     fun = models.BooleanField()
157     objects = PersonManager()
158-
159+    objects_second = PersonManagerSecond(ManagerQuerySet, ['get_fun_people', 'get_not_fun_people'])
160+    objects_third = PersonManagerSecond(ManagerQuerySetMaster, ['get_fun_people', 'get_not_fun_people'])
161+   
162     def __unicode__(self):
163         return u"%s %s" % (self.first_name, self.last_name)
164