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:
parent
64cb7da150
commit
492d2146da
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue