From ad2eb44d297ed2b3decd59a97090ca70266f04c7 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.
---
django/db/models/base.py | 16 +++++++---------
django/db/models/manager.py | 11 -----------
2 files changed, 7 insertions(+), 20 deletions(-)
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 181d845..a881f56 100644
a
|
b
|
from django.db.models.options import Options, AdminOptions
|
15 | 15 | from django.db import connection, transaction |
16 | 16 | from django.db.models import signals |
17 | 17 | from django.db.models.loading import register_models, get_model |
| 18 | from django.db.models.manager import Manager |
18 | 19 | from django.dispatch import dispatcher |
19 | 20 | from django.utils.datastructures import SortedDict |
20 | 21 | from django.utils.functional import curry |
… |
… |
class ModelBase(type):
|
65 | 66 | if not hasattr(meta, 'get_latest_by'): |
66 | 67 | new_class._meta.get_latest_by = base_meta.get_latest_by |
67 | 68 | |
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 | 69 | if getattr(new_class._meta, 'app_label', None) is None: |
75 | 70 | # Figure out the app_label by looking one level up. |
76 | 71 | # For 'django.contrib.sites.models', this would be 'sites'. |
… |
… |
class ModelBase(type):
|
106 | 101 | new_class.add_to_class(attr_name, field) |
107 | 102 | new_class._meta.parents[base] = field |
108 | 103 | else: |
109 | | # The abstract base class case. |
| 104 | # Copy fields from the abstract base class. |
110 | 105 | names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) |
111 | 106 | for field in base._meta.local_fields + base._meta.local_many_to_many: |
112 | 107 | if field.name in names: |
… |
… |
class ModelBase(type):
|
114 | 109 | % (field.name, name, base.__name__)) |
115 | 110 | new_class.add_to_class(field.name, copy.deepcopy(field)) |
116 | 111 | |
| 112 | # Copy managers from the abstract base class. |
| 113 | for attr, value in ((attr, getattr(base, attr)) for attr in dir(base)): |
| 114 | if value == getattr(new_class, attr) and isinstance(value, Manager): |
| 115 | new_class.add_to_class(attr, copy.copy(value)) |
| 116 | |
117 | 117 | if abstract: |
118 | 118 | # Abstract base models can't be instantiated and don't appear in |
119 | 119 | # the list of models for an app. We do the final setup for them a |
… |
… |
class ModelBase(type):
|
122 | 122 | new_class.Meta = attr_meta |
123 | 123 | return new_class |
124 | 124 | |
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 | 125 | new_class._prepare() |
128 | 126 | register_models(new_class._meta.app_label, new_class) |
129 | 127 | |
diff --git a/django/db/models/manager.py b/django/db/models/manager.py
index 3a9da34..697c0f9 100644
a
|
b
|
class Manager(object):
|
36 | 36 | if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter: |
37 | 37 | model._default_manager = self |
38 | 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 |
49 | | |
50 | 39 | ####################### |
51 | 40 | # PROXIES TO QUERYSET # |
52 | 41 | ####################### |