mirror of
https://github.com/django/django.git
synced 2025-06-10 22:19:13 +00:00
magic-removal: Implemented hook for custom managers
git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1647 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
af96c19be2
commit
e18d87f84e
@ -543,16 +543,23 @@ get_module_name = lambda class_name: class_name.lower() + 's'
|
|||||||
get_verbose_name = lambda class_name: re.sub('([A-Z])', ' \\1', class_name).lower().strip()
|
get_verbose_name = lambda class_name: re.sub('([A-Z])', ' \\1', class_name).lower().strip()
|
||||||
|
|
||||||
class Manager(object):
|
class Manager(object):
|
||||||
def __init__(self, model_class):
|
|
||||||
self.klass = model_class
|
# 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):
|
def __get__(self, instance, type=None):
|
||||||
if instance != None:
|
if instance != None:
|
||||||
raise AttributeError, "Manager isn't accessible via %s instances" % self.klass.__name__
|
raise AttributeError, "Manager isn't accessible via %s instances" % self.klass.__name__
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _prepare(self):
|
def _prepare(self, klass):
|
||||||
# Creates some methods once self.klass._meta has been populated.
|
# Creates some methods once self.klass._meta has been populated.
|
||||||
|
self.klass = klass
|
||||||
if self.klass._meta.get_latest_by:
|
if self.klass._meta.get_latest_by:
|
||||||
self.get_latest = self.__get_latest
|
self.get_latest = self.__get_latest
|
||||||
for f in self.klass._meta.fields:
|
for f in self.klass._meta.fields:
|
||||||
@ -735,7 +742,7 @@ class ModelBase(type):
|
|||||||
"Metaclass for all models"
|
"Metaclass for all models"
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
# If this isn't a subclass of Model, don't do anything special.
|
# If this isn't a subclass of Model, don't do anything special.
|
||||||
if not bases:
|
if not bases or bases == (object,):
|
||||||
return type.__new__(cls, name, bases, attrs)
|
return type.__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -745,18 +752,22 @@ class ModelBase(type):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
meta_attrs = {}
|
meta_attrs = {}
|
||||||
|
|
||||||
# Gather all attributes that are Field instances.
|
# Gather all attributes that are Field or Manager instances.
|
||||||
fields = []
|
fields, managers = [], []
|
||||||
for obj_name, obj in attrs.items():
|
for obj_name, obj in attrs.items():
|
||||||
if isinstance(obj, Field):
|
if isinstance(obj, Field):
|
||||||
obj.set_name(obj_name)
|
obj.set_name(obj_name)
|
||||||
fields.append(obj)
|
fields.append(obj)
|
||||||
del attrs[obj_name]
|
del attrs[obj_name]
|
||||||
|
elif isinstance(obj, Manager):
|
||||||
|
managers.append((obj_name, obj))
|
||||||
|
del attrs[obj_name]
|
||||||
|
|
||||||
# Sort the fields in the order that they were created. The
|
# Sort the fields and managers in the order that they were created. The
|
||||||
# "creation_counter" is needed because metaclasses don't preserve the
|
# "creation_counter" is needed because metaclasses don't preserve the
|
||||||
# attribute order.
|
# attribute order.
|
||||||
fields.sort(lambda x, y: x.creation_counter - y.creation_counter)
|
fields.sort(lambda x, y: x.creation_counter - y.creation_counter)
|
||||||
|
managers.sort(lambda x, y: x[1].creation_counter - y[1].creation_counter)
|
||||||
|
|
||||||
opts = Options(
|
opts = Options(
|
||||||
module_name = meta_attrs.pop('module_name', get_module_name(name)),
|
module_name = meta_attrs.pop('module_name', get_module_name(name)),
|
||||||
@ -788,11 +799,6 @@ class ModelBase(type):
|
|||||||
# Create the class, because we need it to use in currying.
|
# Create the class, because we need it to use in currying.
|
||||||
new_class = type.__new__(cls, name, bases, attrs)
|
new_class = type.__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
# Create the manager.
|
|
||||||
# TODO: Use weakref because of possible memory leak / circular reference.
|
|
||||||
# TODO: Allow for overriding of the name, and custom manager subclasses.
|
|
||||||
new_class.objects = Manager(new_class)
|
|
||||||
|
|
||||||
# Give the class a docstring -- its definition.
|
# Give the class a docstring -- its definition.
|
||||||
if new_class.__doc__ is None:
|
if new_class.__doc__ is None:
|
||||||
new_class.__doc__ = "%s.%s(%s)" % (opts.module_name, name, ", ".join([f.name for f in opts.fields]))
|
new_class.__doc__ = "%s.%s(%s)" % (opts.module_name, name, ", ".join([f.name for f in opts.fields]))
|
||||||
@ -816,8 +822,22 @@ class ModelBase(type):
|
|||||||
opts.db_table = "%s_%s" % (app_label, opts.module_name)
|
opts.db_table = "%s_%s" % (app_label, opts.module_name)
|
||||||
new_class._meta = opts
|
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:
|
||||||
|
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._prepare()
|
new_class._prepare()
|
||||||
new_class.objects._prepare()
|
|
||||||
|
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
@ -1037,7 +1057,7 @@ class Model(object):
|
|||||||
file_name = getattr(self, 'get_%s_filename' % f.name)()
|
file_name = getattr(self, 'get_%s_filename' % f.name)()
|
||||||
# If the file exists and no other object of this type references it,
|
# If the file exists and no other object of this type references it,
|
||||||
# delete it from the filesystem.
|
# delete it from the filesystem.
|
||||||
if os.path.exists(file_name) and not self.objects.get_list(**{'%s__exact' % f.name: getattr(self, f.name)}):
|
if os.path.exists(file_name) and not self._default_manager.get_list(**{'%s__exact' % f.name: getattr(self, f.name)}):
|
||||||
os.remove(file_name)
|
os.remove(file_name)
|
||||||
|
|
||||||
# Run any post-delete hooks.
|
# Run any post-delete hooks.
|
||||||
@ -1059,14 +1079,14 @@ class Model(object):
|
|||||||
kwargs.setdefault('params', []).extend([param, param, getattr(self, self._meta.pk.attname)])
|
kwargs.setdefault('params', []).extend([param, param, getattr(self, self._meta.pk.attname)])
|
||||||
kwargs['order_by'] = [(not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name]
|
kwargs['order_by'] = [(not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name]
|
||||||
kwargs['limit'] = 1
|
kwargs['limit'] = 1
|
||||||
return self.objects.get_object(**kwargs)
|
return self._default_manager.get_object(**kwargs)
|
||||||
|
|
||||||
def __get_next_or_previous_in_order(self, is_next):
|
def __get_next_or_previous_in_order(self, is_next):
|
||||||
cachename = "__%s_order_cache" % is_next
|
cachename = "__%s_order_cache" % is_next
|
||||||
if not hasattr(self, cachename):
|
if not hasattr(self, cachename):
|
||||||
op = is_next and '>' or '<'
|
op = is_next and '>' or '<'
|
||||||
order_field = self.order_with_respect_to
|
order_field = self.order_with_respect_to
|
||||||
obj = self.objects.get_object(order_by=('_order',),
|
obj = self._default_manager.get_object(order_by=('_order',),
|
||||||
where=['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
|
where=['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
|
||||||
(backend.quote_name('_order'), op, backend.quote_name('_order'),
|
(backend.quote_name('_order'), op, backend.quote_name('_order'),
|
||||||
backend.quote_name(opts.db_table), backend.quote_name(opts.pk.column)),
|
backend.quote_name(opts.db_table), backend.quote_name(opts.pk.column)),
|
||||||
@ -1153,7 +1173,7 @@ class Model(object):
|
|||||||
params = {'%s__%s__exact' % (field_with_rel.rel.field_name, other_field.rel.field_name): val}
|
params = {'%s__%s__exact' % (field_with_rel.rel.field_name, other_field.rel.field_name): val}
|
||||||
else:
|
else:
|
||||||
params = {'%s__exact' % field_with_rel.rel.field_name: val}
|
params = {'%s__exact' % field_with_rel.rel.field_name: val}
|
||||||
retrieved_obj = field_with_rel.rel.to.objects.get_object(**params)
|
retrieved_obj = field_with_rel.rel.to._default_manager.get_object(**params)
|
||||||
setattr(self, cache_var, retrieved_obj)
|
setattr(self, cache_var, retrieved_obj)
|
||||||
return getattr(self, cache_var)
|
return getattr(self, cache_var)
|
||||||
|
|
||||||
@ -1213,7 +1233,7 @@ class Model(object):
|
|||||||
def __get_related(self, method_name, rel_class, rel_field, **kwargs):
|
def __get_related(self, method_name, rel_class, rel_field, **kwargs):
|
||||||
kwargs['%s__%s__exact' % (rel_field.name, rel_field.rel.to._meta.pk.name)] = getattr(self, rel_field.rel.get_related_field().attname)
|
kwargs['%s__%s__exact' % (rel_field.name, rel_field.rel.to._meta.pk.name)] = getattr(self, rel_field.rel.get_related_field().attname)
|
||||||
kwargs.update(rel_field.rel.lookup_overrides)
|
kwargs.update(rel_field.rel.lookup_overrides)
|
||||||
return getattr(rel_class.objects, method_name)(**kwargs)
|
return getattr(rel_class._default_manager, method_name)(**kwargs)
|
||||||
|
|
||||||
def __add_related(self, rel_class, rel_field, *args, **kwargs):
|
def __add_related(self, rel_class, rel_field, *args, **kwargs):
|
||||||
init_kwargs = dict(zip([f.attname for f in rel_class._meta.fields if f != rel_field and not isinstance(f, AutoField)], args))
|
init_kwargs = dict(zip([f.attname for f in rel_class._meta.fields if f != rel_field and not isinstance(f, AutoField)], args))
|
||||||
@ -1238,7 +1258,7 @@ class Model(object):
|
|||||||
# Examples: Album.get_song(), Album.get_song_list(), Album.get_song_count()
|
# Examples: Album.get_song(), Album.get_song_list(), Album.get_song_count()
|
||||||
def method_get_related_many_to_many(method_name, opts, rel_mod, rel_field, self, **kwargs):
|
def method_get_related_many_to_many(method_name, opts, rel_mod, rel_field, self, **kwargs):
|
||||||
kwargs['%s__%s__exact' % (rel_field.name, opts.pk.name)] = getattr(self, opts.pk.attname)
|
kwargs['%s__%s__exact' % (rel_field.name, opts.pk.name)] = getattr(self, opts.pk.attname)
|
||||||
return getattr(rel_mod.Klass.objects, method_name)(**kwargs)
|
return getattr(rel_mod.Klass._default_manager, method_name)(**kwargs)
|
||||||
|
|
||||||
# Handles setting many-to-many related objects.
|
# Handles setting many-to-many related objects.
|
||||||
# Example: Album.set_songs()
|
# Example: Album.set_songs()
|
||||||
|
@ -313,7 +313,7 @@ class Field(object):
|
|||||||
return first_choice + list(self.choices)
|
return first_choice + list(self.choices)
|
||||||
rel_model = self.rel.to
|
rel_model = self.rel.to
|
||||||
return first_choice + [(getattr(x, rel_model._meta.pk.attname), str(x))
|
return first_choice + [(getattr(x, rel_model._meta.pk.attname), str(x))
|
||||||
for x in rel_model.objects.get_list(**self.rel._meta.limit_choices_to)]
|
for x in rel_model._default_manager.get_list(**self.rel._meta.limit_choices_to)]
|
||||||
|
|
||||||
def get_choices_default(self):
|
def get_choices_default(self):
|
||||||
if(self.radio_admin):
|
if(self.radio_admin):
|
||||||
|
@ -83,4 +83,9 @@ AttributeError: type object 'Book' has no attribute 'objects'
|
|||||||
[Corvette, Neon]
|
[Corvette, Neon]
|
||||||
>>> Car.fast_cars.get_list()
|
>>> Car.fast_cars.get_list()
|
||||||
[Corvette]
|
[Corvette]
|
||||||
|
|
||||||
|
# Each model class gets a "_default_manager" attribute, which is a reference
|
||||||
|
# to the first manager defined in the class. In this case, it's "cars".
|
||||||
|
>>> Car._default_manager.get_list(order_by=('name',))
|
||||||
|
[Corvette, Neon]
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user