From 20b46983a71825f6fa86d8db5fe9875d8cbc0840 Mon Sep 17 00:00:00 2001
From: Sebastian Noack <sebastian.noack@gmail.com>
Date: Fri, 2 May 2008 13:22:20 +0200
Subject: [PATCH] Now all managers, not only the default manager gets copied to the derived model of an abstract model (#7154).
---
django/db/models/base.py | 14 +++++---------
django/db/models/manager.py | 22 +++++++---------------
django/db/models/options.py | 1 +
3 files changed, 13 insertions(+), 24 deletions(-)
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 181d845..24208f4 100644
a
|
b
|
class ModelBase(type):
|
65 | 65 | if not hasattr(meta, 'get_latest_by'): |
66 | 66 | new_class._meta.get_latest_by = base_meta.get_latest_by |
67 | 67 | |
68 | | old_default_mgr = None |
69 | | if getattr(new_class, '_default_manager', None): |
70 | | # We have a parent who set the default manager. |
71 | | if new_class._default_manager.model._meta.abstract: |
72 | | old_default_mgr = new_class._default_manager |
73 | | new_class._default_manager = None |
74 | 68 | if getattr(new_class._meta, 'app_label', None) is None: |
75 | 69 | # Figure out the app_label by looking one level up. |
76 | 70 | # For 'django.contrib.sites.models', this would be 'sites'. |
… |
… |
class ModelBase(type):
|
106 | 100 | new_class.add_to_class(attr_name, field) |
107 | 101 | new_class._meta.parents[base] = field |
108 | 102 | else: |
109 | | # The abstract base class case. |
| 103 | # Copy fields from the abstract base class. |
110 | 104 | names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) |
111 | 105 | for field in base._meta.local_fields + base._meta.local_many_to_many: |
112 | 106 | if field.name in names: |
… |
… |
class ModelBase(type):
|
114 | 108 | % (field.name, name, base.__name__)) |
115 | 109 | new_class.add_to_class(field.name, copy.deepcopy(field)) |
116 | 110 | |
| 111 | # Copy managers from the abstract base class. |
| 112 | for mgr_attr, mgr in base._meta.base_managers.iteritems(): |
| 113 | new_class.add_to_class(mgr_attr, copy.copy(mgr)) |
| 114 | |
117 | 115 | if abstract: |
118 | 116 | # Abstract base models can't be instantiated and don't appear in |
119 | 117 | # the list of models for an app. We do the final setup for them a |
… |
… |
class ModelBase(type):
|
122 | 120 | new_class.Meta = attr_meta |
123 | 121 | return new_class |
124 | 122 | |
125 | | if old_default_mgr and not new_class._default_manager: |
126 | | new_class._default_manager = old_default_mgr._copy_to_model(new_class) |
127 | 123 | new_class._prepare() |
128 | 124 | register_models(new_class._meta.app_label, new_class) |
129 | 125 | |
diff --git a/django/db/models/manager.py b/django/db/models/manager.py
index 3a9da34..5f0872e 100644
a
|
b
|
class Manager(object):
|
31 | 31 | |
32 | 32 | def contribute_to_class(self, model, name): |
33 | 33 | # TODO: Use weakref because of possible memory leak / circular reference. |
34 | | self.model = model |
35 | | setattr(model, name, ManagerDescriptor(self)) |
36 | | if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter: |
37 | | model._default_manager = self |
38 | | |
39 | | def _copy_to_model(self, model): |
40 | | """ |
41 | | Makes a copy of the manager and assigns it to 'model', which should be |
42 | | a child of the existing model (used when inheriting a manager from an |
43 | | abstract base class). |
44 | | """ |
45 | | assert issubclass(model, self.model) |
46 | | mgr = copy.copy(self) |
47 | | mgr.model = model |
48 | | return mgr |
| 34 | if not model._meta.abstract: |
| 35 | self.model = model |
| 36 | setattr(model, name, ManagerDescriptor(self)) |
| 37 | if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter: |
| 38 | model._default_manager = self |
| 39 | else: |
| 40 | model._meta.base_managers[name] = self |
49 | 41 | |
50 | 42 | ####################### |
51 | 43 | # PROXIES TO QUERYSET # |
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 5802ead..d1feed9 100644
a
|
b
|
class Options(object):
|
44 | 44 | self.one_to_one_field = None |
45 | 45 | self.abstract = False |
46 | 46 | self.parents = SortedDict() |
| 47 | self.base_managers = SortedDict() |
47 | 48 | |
48 | 49 | def contribute_to_class(self, cls, name): |
49 | 50 | cls._meta = self |