magic-removal: Added descriptor lookup support for reverse many-to-many relationships -- e.g. site_obj.article_set. For the time being, site_obj.get_article_list(), site_obj.get_article_count(), etc., still work.
git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2144 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
322336c382
commit
90a49140a5
|
@ -67,33 +67,36 @@ class RelatedObjectDescriptor(object):
|
||||||
# managers available as attributes on a model class.
|
# managers available as attributes on a model class.
|
||||||
# In the example "poll.choice_set", the choice_set attribute is a
|
# In the example "poll.choice_set", the choice_set attribute is a
|
||||||
# RelatedObjectDescriptor instance.
|
# RelatedObjectDescriptor instance.
|
||||||
def __init__(self, related):
|
def __init__(self, related, rel_type):
|
||||||
self.related = related # RelatedObject instance
|
self.related = related # RelatedObject instance
|
||||||
self.manager = None
|
self.rel_type = rel_type # Either 'o2m' or 'm2m'
|
||||||
|
|
||||||
def __get__(self, instance, instance_type=None):
|
def __get__(self, instance, instance_type=None):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
raise AttributeError, "Manager must be accessed via instance"
|
raise AttributeError, "Manager must be accessed via instance"
|
||||||
else:
|
else:
|
||||||
if not self.manager:
|
# Dynamically create a class that subclasses the related
|
||||||
# Dynamically create a class that subclasses the related
|
# model's default manager.
|
||||||
# model's default manager.
|
manager = types.ClassType('RelatedManager', (self.related.model._default_manager.__class__,), {})()
|
||||||
self.manager = types.ClassType('RelatedManager', (self.related.model._default_manager.__class__,), {})()
|
|
||||||
|
|
||||||
# Set core_filters on the new manager to limit it to the
|
# Set core_filters on the new manager to limit it to the
|
||||||
# foreign-key relationship.
|
# foreign-key relationship.
|
||||||
rel_field = self.related.field
|
rel_field = self.related.field
|
||||||
self.manager.core_filters = {'%s__%s__exact' % (rel_field.name, rel_field.rel.to._meta.pk.name): getattr(instance, rel_field.rel.get_related_field().attname)}
|
|
||||||
|
|
||||||
# Prepare the manager.
|
if self.rel_type == 'o2m':
|
||||||
# TODO: Fix this hack?
|
manager.core_filters = {'%s__%s__exact' % (rel_field.name, rel_field.rel.to._meta.pk.name): getattr(instance, rel_field.rel.get_related_field().attname)}
|
||||||
# We're setting self.manager.klass here because
|
else:
|
||||||
# self.manager._prepare() expects that self.manager.klass is
|
manager.core_filters = {'%s__%s__exact' % (rel_field.name, instance_type._meta.pk.name): instance._get_pk_val()}
|
||||||
# set. This is slightly hackish.
|
|
||||||
self.manager.klass = self.related.model
|
|
||||||
self.manager._prepare()
|
|
||||||
|
|
||||||
return self.manager
|
# Prepare the manager.
|
||||||
|
# TODO: Fix this hack?
|
||||||
|
# We're setting self.manager.klass here because
|
||||||
|
# self.manager._prepare() expects that self.manager.klass is
|
||||||
|
# set. This is slightly hackish.
|
||||||
|
manager.klass = self.related.model
|
||||||
|
manager._prepare()
|
||||||
|
|
||||||
|
return manager
|
||||||
|
|
||||||
class ForeignKey(RelatedField, Field):
|
class ForeignKey(RelatedField, Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
|
@ -185,12 +188,12 @@ class ForeignKey(RelatedField, Field):
|
||||||
setattr(cls, 'get_%s' % self.name, curry(cls._get_foreign_key_object, field_with_rel=self))
|
setattr(cls, 'get_%s' % self.name, curry(cls._get_foreign_key_object, field_with_rel=self))
|
||||||
|
|
||||||
def contribute_to_related_class(self, cls, related):
|
def contribute_to_related_class(self, cls, related):
|
||||||
setattr(cls, related.get_accessor_name(), RelatedObjectDescriptor(related))
|
setattr(cls, related.get_accessor_name(), RelatedObjectDescriptor(related, 'o2m'))
|
||||||
|
|
||||||
# TODO: Delete the rest of this function and RelatedObject.OLD_get_accessor_name()
|
# TODO: Delete the rest of this function and RelatedObject.OLD_get_accessor_name()
|
||||||
# to remove support for old-style related lookup.
|
# to remove support for old-style related lookup.
|
||||||
|
|
||||||
rel_obj_name = related.OLD_get_accessor_name
|
rel_obj_name = related.OLD_get_accessor_name()
|
||||||
|
|
||||||
# Add "get_thingie" methods for many-to-one related objects.
|
# Add "get_thingie" methods for many-to-one related objects.
|
||||||
# EXAMPLE: Poll.get_choice()
|
# EXAMPLE: Poll.get_choice()
|
||||||
|
@ -336,7 +339,13 @@ class ManyToManyField(RelatedField, Field):
|
||||||
setattr(cls, 'set_%s' % self.name, curry(cls._set_many_to_many_objects, field_with_rel=self))
|
setattr(cls, 'set_%s' % self.name, curry(cls._set_many_to_many_objects, field_with_rel=self))
|
||||||
|
|
||||||
def contribute_to_related_class(self, cls, related):
|
def contribute_to_related_class(self, cls, related):
|
||||||
|
setattr(cls, related.get_accessor_name(), RelatedObjectDescriptor(related, 'm2m'))
|
||||||
|
|
||||||
|
# TODO: Delete the rest of this function and RelatedObject.OLD_get_accessor_name()
|
||||||
|
# to remove support for old-style related lookup.
|
||||||
|
|
||||||
rel_obj_name = related.OLD_get_accessor_name()
|
rel_obj_name = related.OLD_get_accessor_name()
|
||||||
|
|
||||||
setattr(cls, 'get_%s' % rel_obj_name, curry(cls._get_related_many_to_many, method_name='get_object', rel_class=related.model, rel_field=related.field))
|
setattr(cls, 'get_%s' % rel_obj_name, curry(cls._get_related_many_to_many, method_name='get_object', rel_class=related.model, rel_field=related.field))
|
||||||
setattr(cls, 'get_%s_count' % rel_obj_name, curry(cls._get_related_many_to_many, method_name='get_count', rel_class=related.model, rel_field=related.field))
|
setattr(cls, 'get_%s_count' % rel_obj_name, curry(cls._get_related_many_to_many, method_name='get_count', rel_class=related.model, rel_field=related.field))
|
||||||
setattr(cls, 'get_%s_list' % rel_obj_name, curry(cls._get_related_many_to_many, method_name='get_list', rel_class=related.model, rel_field=related.field))
|
setattr(cls, 'get_%s_list' % rel_obj_name, curry(cls._get_related_many_to_many, method_name='get_list', rel_class=related.model, rel_field=related.field))
|
||||||
|
|
Loading…
Reference in New Issue