From 0e692fda9ca57909216e68a998f2752885c23725 Mon Sep 17 00:00:00 2001
From: Malcolm Tredinnick <malcolm.tredinnick@gmail.com>
Date: Thu, 26 Jun 2008 10:50:25 +0000
Subject: [PATCH] Fixed the way symmetrical many-to-many relations are recorded
 in the Options class.

These types of relations don't have reverse accessor names, so that name can be
used by a normal field on the model. Fixed #7107.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7764 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/db/models/options.py             | 11 +++++++----
 tests/regressiontests/queries/models.py | 13 +++++++++++++
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/django/db/models/options.py b/django/db/models/options.py
index bc1aec62c1..c2313f221f 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -274,14 +274,17 @@ class Options(object):
         """
         Initialises the field name -> field object mapping.
         """
-        cache = dict([(f.name, (f, m, True, False)) for f, m in
-                self.get_fields_with_model()])
-        for f, model in self.get_m2m_with_model():
-            cache[f.name] = (f, model, True, True)
+        cache = {}
+        # We intentionally handle related m2m objects first so that symmetrical
+        # m2m accessor names can be overridden, if necessary.
         for f, model in self.get_all_related_m2m_objects_with_model():
             cache[f.field.related_query_name()] = (f, model, False, True)
         for f, model in self.get_all_related_objects_with_model():
             cache[f.field.related_query_name()] = (f, model, False, False)
+        for f, model in self.get_m2m_with_model():
+            cache[f.name] = (f, model, True, True)
+        for f, model in self.get_fields_with_model():
+            cache[f.name] = (f, model, True, False)
         if self.order_with_respect_to:
             cache['_order'] = OrderWrt(), None, True, False
         if app_cache_ready():
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index a3e5561b86..cfbaf773d6 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -90,6 +90,15 @@ class Number(models.Model):
     def __unicode__(self):
         return unicode(self.num)
 
+# Symmetrical m2m field with a normal field using the reverse accesor name
+# ("valid").
+class Valid(models.Model):
+    valid = models.CharField(max_length=10)
+    parent = models.ManyToManyField('self')
+
+    class Meta:
+        ordering = ['valid']
+
 # Some funky cross-linked models for testing a couple of infinite recursion
 # cases.
 class X(models.Model):
@@ -768,5 +777,9 @@ just count the number of results).
 >>> len(Tag.objects.order_by('parent__name'))
 5
 
+Bug #7107 -- this shouldn't create an infinite loop.
+>>> Valid.objects.all()
+[]
+
 """}