Changeset 8851
- Timestamp:
- 09/02/08 04:04:54 (3 months ago)
- Files:
-
- django/trunk/django/db/models/base.py (modified) (3 diffs)
- django/trunk/django/db/models/manager.py (modified) (3 diffs)
- django/trunk/django/db/models/options.py (modified) (1 diff)
- django/trunk/docs/topics/db/managers.txt (modified) (1 diff)
- django/trunk/tests/regressiontests/managers_regress (added)
- django/trunk/tests/regressiontests/managers_regress/__init__.py (added)
- django/trunk/tests/regressiontests/managers_regress/models.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/db/models/base.py
r8674 r8851 68 68 new_class._meta.get_latest_by = base_meta.get_latest_by 69 69 70 old_default_mgr = None71 70 if getattr(new_class, '_default_manager', None): 72 # We have a parent who set the default manager.73 if new_class._default_manager.model._meta.abstract:74 old_default_mgr = new_class._default_manager75 71 new_class._default_manager = None 76 72 … … 112 108 new_class.add_to_class(field.name, copy.deepcopy(field)) 113 109 110 # Inherit managers from the abstract base classes. 111 base_managers = base._meta.abstract_managers 112 base_managers.sort() 113 for _, mgr_name, manager in base_managers: 114 val = getattr(new_class, mgr_name, None) 115 if not val or val is manager: 116 new_manager = manager._copy_to_model(new_class) 117 new_class.add_to_class(mgr_name, new_manager) 114 118 if abstract: 115 119 # Abstract base models can't be instantiated and don't appear in … … 120 124 return new_class 121 125 122 if old_default_mgr and not new_class._default_manager:123 new_class._default_manager = old_default_mgr._copy_to_model(new_class)124 126 new_class._prepare() 125 127 register_models(new_class._meta.app_label, new_class) django/trunk/django/db/models/manager.py
r8223 r8851 24 24 def __init__(self): 25 25 super(Manager, self).__init__() 26 # Increase the creation counter, and save our local copy. 27 self.creation_counter = Manager.creation_counter 28 Manager.creation_counter += 1 26 self._set_creation_counter() 29 27 self.model = None 28 self._inherited = False 30 29 31 30 def contribute_to_class(self, model, name): … … 35 34 if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter: 36 35 model._default_manager = self 36 if model._meta.abstract or self._inherited: 37 model._meta.abstract_managers.append((self.creation_counter, name, 38 self)) 39 40 def _set_creation_counter(self): 41 """ 42 Sets the creation counter value for this instance and increments the 43 class-level copy. 44 """ 45 self.creation_counter = Manager.creation_counter 46 Manager.creation_counter += 1 37 47 38 48 def _copy_to_model(self, model): … … 44 54 assert issubclass(model, self.model) 45 55 mgr = copy.copy(self) 56 mgr._set_creation_counter() 46 57 mgr.model = model 58 mgr._inherited = True 47 59 return mgr 48 60 django/trunk/django/db/models/options.py
r8730 r8851 45 45 self.parents = SortedDict() 46 46 self.duplicate_targets = {} 47 # Managers that have been inherited from abstract base classes. These 48 # are passed onto any children. 49 self.abstract_managers = [] 47 50 48 51 def contribute_to_class(self, cls, name): django/trunk/docs/topics/db/managers.txt
r8506 r8851 190 190 191 191 ... 192 193 Custom managers and model inheritance 194 ------------------------------------- 195 196 Class inheritance and model managers aren't quite a perfect match for each 197 other. Managers are often specific to the classes they are defined on and 198 inheriting them in subclasses isn't necessarily a good idea. Also, because the 199 first manager declared is the *default manager*, it is important to allow that 200 to be controlled. So here's how Django handles custom managers and 201 :ref:`model inheritance <model-inheritance>`: 202 203 1. Managers defined on non-abstract base classes are *not* inherited by 204 child classes. If you want to reuse a manager from a non-abstract base, 205 redeclare it explicitly on the child class. These sorts of managers are 206 likely to be fairly specific to the class they are defined on, so 207 inheriting them can often lead to unexpected results (particularly as 208 far as the default manager goes). Therefore, they aren't passed onto 209 child classes. 210 211 2. Managers from abstract base classes are always inherited by the child 212 class, using Python's normal name resolution order (names on the child 213 class override all others; then come names on the first parent class, 214 and so on). Abstract base classes are designed to capture information 215 and behaviour that is common to their child classes. Defining common 216 managers is an appropriate part of this common information. 217 218 3. The default manager on a class is either the first manager declared on 219 the class, if that exists, or the default manager of the first abstract 220 base class in the parent hierarchy, if that exists. If no default 221 manager is explicitly declared, Django's normal default manager is 222 used. 223
