Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

magic-removal: Refs #1346 -- Refactored query logic for m2m descripto…

…r 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
  • Loading branch information...
commit 492d2146da4359182ee0bd721c1217980ae545fe 1 parent 64cb7da
@freakboy3742 freakboy3742 authored
View
33 django/db/models/fields/related.py
@@ -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 @@ def do_related_class(self, other, cls):
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 @@ def clear(self):
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 @@ def get_query_set(self):
],
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 @@ def clear(self):
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 @@ def _get_m2m_db_table(self, opts):
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
2  django/db/models/query.py
@@ -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
6 django/db/models/related.py
@@ -74,9 +74,3 @@ def get_accessor_name(self):
# 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()
Please sign in to comment.
Something went wrong with that request. Please try again.