magic-removal: Refs #1346 -- Refactored query logic for m2m descriptor fields, and added logic to m2m name methods to allow m2m_recursive tests to create a valid SQL table.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2381 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2006-02-24 10:25:02 +00:00
parent 64cb7da150
commit 492d2146da
3 changed files with 29 additions and 12 deletions

View File

@ -46,6 +46,10 @@ def manipulator_valid_rel_key(f, self, field_data, all_data):
class RelatedField(object):
def contribute_to_class(self, cls, name):
sup = super(RelatedField, self)
# Add an accessor to allow easy determination of the related query path for this field
self.related_query_name = curry(self._get_related_query_name, cls._meta)
if hasattr(sup, 'contribute_to_class'):
sup.contribute_to_class(cls, name)
other = self.rel.to
@ -66,6 +70,12 @@ class RelatedField(object):
related = RelatedObject(other, cls, self)
self.contribute_to_related_class(other, related)
def _get_related_query_name(self, opts):
# This method defines the name that can be used to identify this related object
# in a table-spanning query. It uses the lower-cased object_name by default,
# but this can be overridden with the "related_name" option.
return self.rel.related_name or opts.object_name.lower()
class SingleRelatedObjectDescriptor(object):
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
@ -241,9 +251,9 @@ class ManyRelatedObjectsDescriptor(object):
manager = RelatedManager()
if self.rel_type == 'o2m':
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)}
manager.core_filters = {'%s__pk' % rel_field.name: getattr(instance, rel_field.rel.get_related_field().attname)}
else:
manager.core_filters = {'%s__%s__exact' % (rel_field.name, instance_type._meta.pk.name): instance._get_pk_val()}
manager.core_filters = {'%s__pk' % rel_field.name: instance._get_pk_val()}
manager.model = self.related.model
@ -285,6 +295,8 @@ class ReverseManyRelatedObjectsDescriptor(object):
],
params = [instance._get_pk_val()]
)
return superclass.get_query_set(self).filter(**(self.core_filters))
def add(self, *objs, **kwargs):
_add_m2m_items(self, superclass, rel_model, join_table, source_col_name,
target_col_name, instance._get_pk_val(), *objs, **kwargs)
@ -300,6 +312,9 @@ class ReverseManyRelatedObjectsDescriptor(object):
clear.alters_data = True
manager = RelatedManager()
manager.core_filters = {'%s__pk' % self.field.related_query_name() : instance._get_pk_val()}
manager.model = rel_model
return manager
@ -470,11 +485,19 @@ class ManyToManyField(RelatedField, Field):
def _get_m2m_column_name(self, related):
"Function that can be curried to provide the source column name for the m2m table"
return related.model._meta.object_name.lower() + '_id'
# If this is an m2m relation to self, avoid the inevitable name clash
if related.model == related.parent_model:
return 'from_' + related.model._meta.object_name.lower() + '_id'
else:
return related.model._meta.object_name.lower() + '_id'
def _get_m2m_reverse_name(self, related):
"Function that can be curried to provide the related column name for the m2m table"
return related.parent_model._meta.object_name.lower() + '_id'
# If this is an m2m relation to self, avoid the inevitable name clash
if related.model == related.parent_model:
return 'to_' + related.parent_model._meta.object_name.lower() + '_id'
else:
return related.parent_model._meta.object_name.lower() + '_id'
def isValidIDList(self, field_data, all_data):
"Validates that the value is a valid list of foreign keys"

View File

@ -613,7 +613,7 @@ def find_field(name, field_list, related_query):
Returns None if there are no matches, or several matches.
"""
if related_query:
matches = [f for f in field_list if f.get_query_name() == name]
matches = [f for f in field_list if f.field.related_query_name() == name]
else:
matches = [f for f in field_list if f.name == name]
if len(matches) != 1:

View File

@ -74,9 +74,3 @@ class RelatedObject(object):
# many-to-many objects. It uses the lower-cased object_name + "_set",
# but this can be overridden with the "related_name" option.
return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
def get_query_name(self):
# This method defines the name that can be used to identify this related object
# in a table-spanning query. It uses the lower-cased object_name by default,
# but this can be overridden with the "related_name" option.
return self.field.rel.related_name or self.opts.object_name.lower()