From 7aeeae67eead6cc46c8804c37ad77a7db97b0873 Mon Sep 17 00:00:00 2001 From: Robert Wittams Date: Fri, 16 Dec 2005 15:14:12 +0000 Subject: [PATCH] Seperate managers from their descriptors. git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1697 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/base.py | 27 ++++++++++++++------------- django/db/models/manager.py | 33 +++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/django/db/models/base.py b/django/db/models/base.py index dc3d657126..5b842048da 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -2,7 +2,7 @@ from django.db.models.manipulators import ManipulatorDescriptor, ModelAddManipul from django.db.models.fields import Field, DateField, FileField, ImageField, AutoField from django.db.models.fields import OneToOne, ManyToOne, ManyToMany, RECURSIVE_RELATIONSHIP_CONSTANT from django.db.models.related import RelatedObject -from django.db.models.manager import Manager +from django.db.models.manager import Manager, ManagerDescriptor from django.db.models.query import orderlist2sql from django.db.models.options import Options from django.db import connection, backend @@ -106,20 +106,14 @@ class ModelBase(type): opts.db_table = "%s_%s" % (app_label, opts.module_name) new_class._meta = opts - # Create the default manager, if needed. - # TODO: Use weakref because of possible memory leak / circular reference. - if managers: - for m_name, m in managers: - m._prepare(new_class) - setattr(new_class, m_name, m) - new_class._default_manager = managers[0][1] - else: + for m_name, m in managers: + new_class.add_to_class(m_name, m) + + if not hasattr(new_class, '_default_manager'): + # Create the default manager, if needed. if hasattr(new_class, 'objects'): raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % name - m = Manager() - m._prepare(new_class) - new_class.objects = m - new_class._default_manager = m + new_class.add_to_class('objects', Manager()) new_class._prepare() @@ -139,6 +133,13 @@ class ModelBase(type): class Model(object): __metaclass__ = ModelBase + def add_to_class(cls, name, attribute): + if hasattr(attribute, 'contribute_to_class'): + attribute.contribute_to_class(cls, name) + else: + setattr(cls, name, attribute) + add_to_class = classmethod(add_to_class) + AddManipulator = ManipulatorDescriptor('AddManipulator', ModelAddManipulator) ChangeManipulator = ManipulatorDescriptor('ChangeManipulator', ModelChangeManipulator) diff --git a/django/db/models/manager.py b/django/db/models/manager.py index 7cbfa7aaaf..79f1560f8b 100644 --- a/django/db/models/manager.py +++ b/django/db/models/manager.py @@ -8,25 +8,17 @@ from django.db.models.query import handle_legacy_orderlist, orderlist2sql, order # Larger values are slightly faster at the expense of more storage space. GET_ITERATOR_CHUNK_SIZE = 100 - - class Manager(object): - - # Tracks each time a Field instance is created. Used to retain order. + # Tracks each time a Field instance is created. Used to retain order. creation_counter = 0 def __init__(self): # Increase the creation counter, and save our local copy. self.creation_counter = Manager.creation_counter Manager.creation_counter += 1 - - def __get__(self, instance, type=None): - if instance != None: - raise AttributeError, "Manager isn't accessible via %s instances" % self.klass.__name__ - return self - + self.klass = None + def _prepare(self, klass): - # Creates some methods once self.klass._meta has been populated. self.klass = klass if self.klass._meta.get_latest_by: self.get_latest = self.__get_latest @@ -34,6 +26,14 @@ class Manager(object): if isinstance(f, DateField): setattr(self, 'get_%s_list' % f.name, curry(self.__get_date_list, f)) + def contribute_to_class(self, klass, name): + # TODO: Use weakref because of possible memory leak / circular reference. + self._prepare(klass) + setattr(klass,name, ManagerDescriptor(self)) + if not hasattr(klass, '_default_manager') or \ + self.creation_counter < klass._default_manager.creation_counter: + klass._default_manager = self + def _get_sql_clause(self, **kwargs): def quote_only_if_word(word): if ' ' in word: @@ -204,4 +204,13 @@ class Manager(object): # We have to manually run typecast_timestamp(str()) on the results, because # MySQL doesn't automatically cast the result of date functions as datetime # objects -- MySQL returns the values as strings, instead. - return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()] + return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()] + +class ManagerDescriptor(object): + def __init__(self, manager): + self.manager = manager + + def __get__(self, instance, type=None): + if instance != None: + raise AttributeError, "Manager isn't accessible via %s instances" % type.__name__ + return self.manager \ No newline at end of file