1
0
mirror of https://github.com/django/django.git synced 2025-06-05 03:29:12 +00:00

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): class RelatedField(object):
def contribute_to_class(self, cls, name): def contribute_to_class(self, cls, name):
sup = super(RelatedField, self) 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'): if hasattr(sup, 'contribute_to_class'):
sup.contribute_to_class(cls, name) sup.contribute_to_class(cls, name)
other = self.rel.to other = self.rel.to
@ -66,6 +70,12 @@ class RelatedField(object):
related = RelatedObject(other, cls, self) related = RelatedObject(other, cls, self)
self.contribute_to_related_class(other, related) 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): class SingleRelatedObjectDescriptor(object):
# This class provides the functionality that makes the related-object # This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have # managers available as attributes on a model class, for fields that have
@ -241,9 +251,9 @@ class ManyRelatedObjectsDescriptor(object):
manager = RelatedManager() manager = RelatedManager()
if self.rel_type == 'o2m': 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: 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 manager.model = self.related.model
@ -285,6 +295,8 @@ class ReverseManyRelatedObjectsDescriptor(object):
], ],
params = [instance._get_pk_val()] params = [instance._get_pk_val()]
) )
return superclass.get_query_set(self).filter(**(self.core_filters))
def add(self, *objs, **kwargs): def add(self, *objs, **kwargs):
_add_m2m_items(self, superclass, rel_model, join_table, source_col_name, _add_m2m_items(self, superclass, rel_model, join_table, source_col_name,
target_col_name, instance._get_pk_val(), *objs, **kwargs) target_col_name, instance._get_pk_val(), *objs, **kwargs)
@ -300,6 +312,9 @@ class ReverseManyRelatedObjectsDescriptor(object):
clear.alters_data = True clear.alters_data = True
manager = RelatedManager() manager = RelatedManager()
manager.core_filters = {'%s__pk' % self.field.related_query_name() : instance._get_pk_val()}
manager.model = rel_model manager.model = rel_model
return manager return manager
@ -470,11 +485,19 @@ class ManyToManyField(RelatedField, Field):
def _get_m2m_column_name(self, related): def _get_m2m_column_name(self, related):
"Function that can be curried to provide the source column name for the m2m table" "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): def _get_m2m_reverse_name(self, related):
"Function that can be curried to provide the related column name for the m2m table" "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): def isValidIDList(self, field_data, all_data):
"Validates that the value is a valid list of foreign keys" "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. Returns None if there are no matches, or several matches.
""" """
if related_query: 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: else:
matches = [f for f in field_list if f.name == name] matches = [f for f in field_list if f.name == name]
if len(matches) != 1: 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", # many-to-many objects. It uses the lower-cased object_name + "_set",
# but this can be overridden with the "related_name" option. # but this can be overridden with the "related_name" option.
return self.field.rel.related_name or (self.opts.object_name.lower() + '_set') 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()