Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

QuerySet.as_manager()

  • Loading branch information...
commit 283af213d1873cefd642b6d9aeb97f285ef227c4 1 parent 3632d28
Anssi Kääriäinen authored
1  django/db/models/__init__.py
@@ -5,6 +5,7 @@
5 5 from django.db.models.query import Q
6 6 from django.db.models.expressions import F
7 7 from django.db.models.manager import Manager
  8 +from django.db.models.query import QuerySet
8 9 from django.db.models.base import Model
9 10 from django.db.models.aggregates import *
10 11 from django.db.models.fields import *
118 django/db/models/manager.py
@@ -55,12 +55,13 @@ class RenameManagerMethods(RenameMethodsBase):
55 55 )
56 56
57 57
58   -class Manager(six.with_metaclass(RenameManagerMethods)):
  58 +class _Manager(six.with_metaclass(RenameManagerMethods)):
59 59 # Tracks each time a Manager instance is created. Used to retain order.
60 60 creation_counter = 0
  61 + queryset_class = QuerySet
61 62
62 63 def __init__(self):
63   - super(Manager, self).__init__()
  64 + super(_Manager, self).__init__()
64 65 self._set_creation_counter()
65 66 self.model = None
66 67 self._inherited = False
@@ -91,8 +92,8 @@ def _set_creation_counter(self):
91 92 Sets the creation counter value for this instance and increments the
92 93 class-level copy.
93 94 """
94   - self.creation_counter = Manager.creation_counter
95   - Manager.creation_counter += 1
  95 + self.creation_counter = _Manager.creation_counter
  96 + _Manager.creation_counter += 1
96 97
97 98 def _copy_to_model(self, model):
98 99 """
@@ -116,118 +117,17 @@ def db_manager(self, using):
116 117 def db(self):
117 118 return self._db or router.db_for_read(self.model)
118 119
119   - #######################
120   - # PROXIES TO QUERYSET #
121   - #######################
122   -
123 120 def get_queryset(self):
124 121 """Returns a new QuerySet object. Subclasses can override this method
125 122 to easily customize the behavior of the Manager.
126 123 """
127   - return QuerySet(self.model, using=self._db)
128   -
129   - def none(self):
130   - return self.get_queryset().none()
  124 + return self.queryset_class(self.model, using=self._db)
131 125
132 126 def all(self):
  127 + # All can't be proxied to QuerySet, as prefetch_related is lost on
  128 + # clone().
133 129 return self.get_queryset()
134 130
135   - def count(self):
136   - return self.get_queryset().count()
137   -
138   - def dates(self, *args, **kwargs):
139   - return self.get_queryset().dates(*args, **kwargs)
140   -
141   - def datetimes(self, *args, **kwargs):
142   - return self.get_queryset().datetimes(*args, **kwargs)
143   -
144   - def distinct(self, *args, **kwargs):
145   - return self.get_queryset().distinct(*args, **kwargs)
146   -
147   - def extra(self, *args, **kwargs):
148   - return self.get_queryset().extra(*args, **kwargs)
149   -
150   - def get(self, *args, **kwargs):
151   - return self.get_queryset().get(*args, **kwargs)
152   -
153   - def get_or_create(self, **kwargs):
154   - return self.get_queryset().get_or_create(**kwargs)
155   -
156   - def create(self, **kwargs):
157   - return self.get_queryset().create(**kwargs)
158   -
159   - def bulk_create(self, *args, **kwargs):
160   - return self.get_queryset().bulk_create(*args, **kwargs)
161   -
162   - def filter(self, *args, **kwargs):
163   - return self.get_queryset().filter(*args, **kwargs)
164   -
165   - def aggregate(self, *args, **kwargs):
166   - return self.get_queryset().aggregate(*args, **kwargs)
167   -
168   - def annotate(self, *args, **kwargs):
169   - return self.get_queryset().annotate(*args, **kwargs)
170   -
171   - def complex_filter(self, *args, **kwargs):
172   - return self.get_queryset().complex_filter(*args, **kwargs)
173   -
174   - def exclude(self, *args, **kwargs):
175   - return self.get_queryset().exclude(*args, **kwargs)
176   -
177   - def in_bulk(self, *args, **kwargs):
178   - return self.get_queryset().in_bulk(*args, **kwargs)
179   -
180   - def iterator(self, *args, **kwargs):
181   - return self.get_queryset().iterator(*args, **kwargs)
182   -
183   - def earliest(self, *args, **kwargs):
184   - return self.get_queryset().earliest(*args, **kwargs)
185   -
186   - def latest(self, *args, **kwargs):
187   - return self.get_queryset().latest(*args, **kwargs)
188   -
189   - def first(self):
190   - return self.get_queryset().first()
191   -
192   - def last(self):
193   - return self.get_queryset().last()
194   -
195   - def order_by(self, *args, **kwargs):
196   - return self.get_queryset().order_by(*args, **kwargs)
197   -
198   - def select_for_update(self, *args, **kwargs):
199   - return self.get_queryset().select_for_update(*args, **kwargs)
200   -
201   - def select_related(self, *args, **kwargs):
202   - return self.get_queryset().select_related(*args, **kwargs)
203   -
204   - def prefetch_related(self, *args, **kwargs):
205   - return self.get_queryset().prefetch_related(*args, **kwargs)
206   -
207   - def values(self, *args, **kwargs):
208   - return self.get_queryset().values(*args, **kwargs)
209   -
210   - def values_list(self, *args, **kwargs):
211   - return self.get_queryset().values_list(*args, **kwargs)
212   -
213   - def update(self, *args, **kwargs):
214   - return self.get_queryset().update(*args, **kwargs)
215   -
216   - def reverse(self, *args, **kwargs):
217   - return self.get_queryset().reverse(*args, **kwargs)
218   -
219   - def defer(self, *args, **kwargs):
220   - return self.get_queryset().defer(*args, **kwargs)
221   -
222   - def only(self, *args, **kwargs):
223   - return self.get_queryset().only(*args, **kwargs)
224   -
225   - def using(self, *args, **kwargs):
226   - return self.get_queryset().using(*args, **kwargs)
227   -
228   - def exists(self, *args, **kwargs):
229   - return self.get_queryset().exists(*args, **kwargs)
230   -
231 131 def _insert(self, objs, fields, **kwargs):
232 132 return insert_query(self.model, objs, fields, **kwargs)
233 133
@@ -237,6 +137,8 @@ def _update(self, values, **kwargs):
237 137 def raw(self, raw_query, params=None, *args, **kwargs):
238 138 return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs)
239 139
  140 +Manager = QuerySet.manager_cls(base_cls=_Manager)
  141 +
240 142
241 143 class ManagerDescriptor(object):
242 144 # This class ensures managers aren't accessible via model instances.
60 django/db/models/query.py
@@ -41,6 +41,33 @@ def __init__(self, model=None, query=None, using=None):
41 41 self._prefetch_done = False
42 42 self._known_related_objects = {} # {rel_field, {pk: rel_obj}}
43 43
  44 + @classmethod
  45 + def manager_cls(cls, base_cls=None):
  46 + """
  47 + Creates a manager class for this QuerySet class.
  48 + """
  49 + def create_method(name):
  50 + def manager_copy(self, *args, **kwargs):
  51 + return getattr(self.get_queryset(), name)(*args, **kwargs)
  52 + return manager_copy
  53 + new_methods = {}
  54 + for name, maybe_copy in cls.__dict__.items():
  55 + if callable(maybe_copy) and getattr(maybe_copy, 'manager', False):
  56 + new_methods[name] = create_method(name)
  57 + if base_cls is None:
  58 + from django.db.models.manager import Manager as base_cls
  59 + manager_cls = type(
  60 + cls.__name__ + 'Manager',
  61 + (base_cls,),
  62 + new_methods)
  63 + manager_cls.queryset_class = cls
  64 + return manager_cls
  65 +
  66 + @classmethod
  67 + def as_manager(cls, base_cls=None):
  68 + manager_cls = cls.manager_cls(base_cls=base_cls)
  69 + return manager_cls()
  70 +
44 71 ########################
45 72 # PYTHON MAGIC METHODS #
46 73 ########################
@@ -254,6 +281,7 @@ def iterator(self):
254 281 setattr(obj, field.name, rel_obj)
255 282
256 283 yield obj
  284 + iterator.manager = True
257 285
258 286 def aggregate(self, *args, **kwargs):
259 287 """
@@ -275,6 +303,7 @@ def aggregate(self, *args, **kwargs):
275 303 is_summary=True)
276 304
277 305 return query.get_aggregation(using=self.db)
  306 + aggregate.manager = True
278 307
279 308 def count(self):
280 309 """
@@ -288,6 +317,7 @@ def count(self):
288 317 return len(self._result_cache)
289 318
290 319 return self.query.get_count(using=self.db)
  320 + count.manager = True
291 321
292 322 def get(self, *args, **kwargs):
293 323 """
@@ -307,6 +337,7 @@ def get(self, *args, **kwargs):
307 337 raise self.model.MultipleObjectsReturned(
308 338 "get() returned more than one %s -- it returned %s!" %
309 339 (self.model._meta.object_name, num))
  340 + get.manager = True
310 341
311 342 def create(self, **kwargs):
312 343 """
@@ -317,6 +348,7 @@ def create(self, **kwargs):
317 348 self._for_write = True
318 349 obj.save(force_insert=True, using=self.db)
319 350 return obj
  351 + create.manager = True
320 352
321 353 def bulk_create(self, objs, batch_size=None):
322 354 """
@@ -355,6 +387,7 @@ def bulk_create(self, objs, batch_size=None):
355 387 self._batched_insert(objs_without_pk, fields, batch_size)
356 388
357 389 return objs
  390 + bulk_create.manager = True
358 391
359 392 def get_or_create(self, **kwargs):
360 393 """
@@ -387,6 +420,7 @@ def get_or_create(self, **kwargs):
387 420 except self.model.DoesNotExist:
388 421 # Re-raise the DatabaseError with its original traceback.
389 422 six.reraise(*exc_info)
  423 + get_or_create.manager = True
390 424
391 425 def _earliest_or_latest(self, field_name=None, direction="-"):
392 426 """
@@ -406,9 +440,11 @@ def _earliest_or_latest(self, field_name=None, direction="-"):
406 440
407 441 def earliest(self, field_name=None):
408 442 return self._earliest_or_latest(field_name=field_name, direction="")
  443 + earliest.manager = True
409 444
410 445 def latest(self, field_name=None):
411 446 return self._earliest_or_latest(field_name=field_name, direction="-")
  447 + latest.manager = True
412 448
413 449 def first(self):
414 450 """
@@ -419,6 +455,7 @@ def first(self):
419 455 return qs[0]
420 456 except IndexError:
421 457 return None
  458 + first.manager = True
422 459
423 460 def last(self):
424 461 """
@@ -429,6 +466,7 @@ def last(self):
429 466 return qs[0]
430 467 except IndexError:
431 468 return None
  469 + last.manager = True
432 470
433 471 def in_bulk(self, id_list):
434 472 """
@@ -441,6 +479,7 @@ def in_bulk(self, id_list):
441 479 return {}
442 480 qs = self.filter(pk__in=id_list).order_by()
443 481 return dict([(obj._get_pk_val(), obj) for obj in qs])
  482 + in_bulk.manager = True
444 483
445 484 def delete(self):
446 485 """
@@ -492,6 +531,7 @@ def update(self, **kwargs):
492 531 self._result_cache = None
493 532 return rows
494 533 update.alters_data = True
  534 + update.manager = True
495 535
496 536 def _update(self, values):
497 537 """
@@ -512,6 +552,7 @@ def exists(self):
512 552 if self._result_cache is None:
513 553 return self.query.has_results(using=self.db)
514 554 return bool(self._result_cache)
  555 + exists.manager = True
515 556
516 557 def _prefetch_related_objects(self):
517 558 # This method can only be called once the result cache has been filled.
@@ -524,6 +565,7 @@ def _prefetch_related_objects(self):
524 565
525 566 def values(self, *fields):
526 567 return self._clone(klass=ValuesQuerySet, setup=True, _fields=fields)
  568 + values.manager = True
527 569
528 570 def values_list(self, *fields, **kwargs):
529 571 flat = kwargs.pop('flat', False)
@@ -534,6 +576,7 @@ def values_list(self, *fields, **kwargs):
534 576 raise TypeError("'flat' is not valid when values_list is called with more than one field.")
535 577 return self._clone(klass=ValuesListQuerySet, setup=True, flat=flat,
536 578 _fields=fields)
  579 + values_list.manager = True
537 580
538 581 def dates(self, field_name, kind, order='ASC'):
539 582 """
@@ -546,6 +589,7 @@ def dates(self, field_name, kind, order='ASC'):
546 589 "'order' must be either 'ASC' or 'DESC'."
547 590 return self._clone(klass=DateQuerySet, setup=True,
548 591 _field_name=field_name, _kind=kind, _order=order)
  592 + dates.manager = True
549 593
550 594 def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
551 595 """
@@ -563,6 +607,7 @@ def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
563 607 tzinfo = None
564 608 return self._clone(klass=DateTimeQuerySet, setup=True,
565 609 _field_name=field_name, _kind=kind, _order=order, _tzinfo=tzinfo)
  610 + datetimes.manager = True
566 611
567 612 def none(self):
568 613 """
@@ -571,6 +616,7 @@ def none(self):
571 616 clone = self._clone()
572 617 clone.query.set_empty()
573 618 return clone
  619 + none.manager = True
574 620
575 621 ##################################################################
576 622 # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
@@ -589,6 +635,7 @@ def filter(self, *args, **kwargs):
589 635 set.
590 636 """
591 637 return self._filter_or_exclude(False, *args, **kwargs)
  638 + filter.manager = True
592 639
593 640 def exclude(self, *args, **kwargs):
594 641 """
@@ -596,6 +643,7 @@ def exclude(self, *args, **kwargs):
596 643 set.
597 644 """
598 645 return self._filter_or_exclude(True, *args, **kwargs)
  646 + exclude.manager = True
599 647
600 648 def _filter_or_exclude(self, negate, *args, **kwargs):
601 649 if args or kwargs:
@@ -625,6 +673,7 @@ def complex_filter(self, filter_obj):
625 673 return clone
626 674 else:
627 675 return self._filter_or_exclude(None, **filter_obj)
  676 + complex_filter.manager = True
628 677
629 678 def select_for_update(self, **kwargs):
630 679 """
@@ -637,6 +686,7 @@ def select_for_update(self, **kwargs):
637 686 obj.query.select_for_update = True
638 687 obj.query.select_for_update_nowait = nowait
639 688 return obj
  689 + select_for_update.manager=True
640 690
641 691 def select_related(self, *fields, **kwargs):
642 692 """
@@ -658,6 +708,7 @@ def select_related(self, *fields, **kwargs):
658 708 else:
659 709 obj.query.select_related = True
660 710 return obj
  711 + select_related.manager = True
661 712
662 713 def prefetch_related(self, *lookups):
663 714 """
@@ -675,6 +726,7 @@ def prefetch_related(self, *lookups):
675 726 else:
676 727 clone._prefetch_related_lookups.extend(lookups)
677 728 return clone
  729 + prefetch_related.manager = True
678 730
679 731 def annotate(self, *args, **kwargs):
680 732 """
@@ -706,6 +758,7 @@ def annotate(self, *args, **kwargs):
706 758 is_summary=False)
707 759
708 760 return obj
  761 + annotate.manager = True
709 762
710 763 def order_by(self, *field_names):
711 764 """
@@ -717,6 +770,7 @@ def order_by(self, *field_names):
717 770 obj.query.clear_ordering(force_empty=False)
718 771 obj.query.add_ordering(*field_names)
719 772 return obj
  773 + order_by.manager = True
720 774
721 775 def distinct(self, *field_names):
722 776 """
@@ -727,6 +781,7 @@ def distinct(self, *field_names):
727 781 obj = self._clone()
728 782 obj.query.add_distinct_fields(*field_names)
729 783 return obj
  784 + distinct.manager = True
730 785
731 786 def extra(self, select=None, where=None, params=None, tables=None,
732 787 order_by=None, select_params=None):
@@ -738,6 +793,7 @@ def extra(self, select=None, where=None, params=None, tables=None,
738 793 clone = self._clone()
739 794 clone.query.add_extra(select, select_params, where, params, tables, order_by)
740 795 return clone
  796 + extra.manager = True
741 797
742 798 def reverse(self):
743 799 """
@@ -746,6 +802,7 @@ def reverse(self):
746 802 clone = self._clone()
747 803 clone.query.standard_ordering = not clone.query.standard_ordering
748 804 return clone
  805 + reverse.manager = True
749 806
750 807 def defer(self, *fields):
751 808 """
@@ -761,6 +818,7 @@ def defer(self, *fields):
761 818 else:
762 819 clone.query.add_deferred_loading(fields)
763 820 return clone
  821 + defer.manager = True
764 822
765 823 def only(self, *fields):
766 824 """
@@ -775,6 +833,7 @@ def only(self, *fields):
775 833 clone = self._clone()
776 834 clone.query.add_immediate_loading(fields)
777 835 return clone
  836 + only.manager = True
778 837
779 838 def using(self, alias):
780 839 """
@@ -783,6 +842,7 @@ def using(self, alias):
783 842 clone = self._clone()
784 843 clone._db = alias
785 844 return clone
  845 + using.manager = True
786 846
787 847 ###################################
788 848 # PUBLIC INTROSPECTION ATTRIBUTES #
16 tests/custom_managers/models.py
@@ -20,12 +20,28 @@ class PersonManager(models.Manager):
20 20 def get_fun_people(self):
21 21 return self.filter(fun=True)
22 22
  23 + def filter(self, *args, **kwargs):
  24 + print("manager:filter")
  25 + return super(PersonManager, self).filter(*args, **kwargs)
  26 +
  27 +class CustomQuerySet(models.QuerySet):
  28 + def filter(self, *args, **kwargs):
  29 + print("custom:filter")
  30 + return super(CustomQuerySet, self).filter(*args, **kwargs)
  31 + filter.manager = True
  32 +
  33 + def bar(self, *args, **kwargs):
  34 + print("custom:bar")
  35 + return self.all()
  36 + bar.manager = True
  37 +
23 38 @python_2_unicode_compatible
24 39 class Person(models.Model):
25 40 first_name = models.CharField(max_length=30)
26 41 last_name = models.CharField(max_length=30)
27 42 fun = models.BooleanField()
28 43 objects = PersonManager()
  44 + other_objects = CustomQuerySet.as_manager(base_cls=PersonManager)
29 45
30 46 def __str__(self):
31 47 return "%s %s" % (self.first_name, self.last_name)
8 tests/custom_managers/tests.py
@@ -17,6 +17,14 @@ def test_manager(self):
17 17 ],
18 18 six.text_type
19 19 )
  20 + self.assertQuerysetEqual(
  21 + Person.other_objects.get_fun_people(), [
  22 + "Bugs Bunny"
  23 + ],
  24 + six.text_type
  25 + )
  26 + print Person.other_objects.filter(fun=False)
  27 + print Person.other_objects.bar()
20 28 # The RelatedManager used on the 'books' descriptor extends the default
21 29 # manager
22 30 self.assertIsInstance(p2.books, PublishedBookManager)

0 comments on commit 283af21

Please sign in to comment.
Something went wrong with that request. Please try again.