Commits

F. Gabriel Gosselin committed dc3c169

Allow the columns referred to as part of a foreign key (ex. id field) to be renamed
This is of limited use in practice, but a stepping stone for table renames.

Comments (0)

Files changed (2)

south/db/mysql.py

             self.delete_foreign_key(table_name, column_name)
         except ValueError:
             pass # If no foreign key on column, OK because it checks first
-
+        try:
+            reverse = self._lookup_reverse_constraint(table_name, column_name)
+            for cname, rtable, rcolumn in reverse:
+                self.delete_foreign_key(rtable, rcolumn)
+        except DryRunError:
+            pass
         return func(self, table_name, column_name, *args, **opts)
     return _column_rm
 
     def _column_cp(self, table_name, column_old, column_new, *args, **opts):
         try:
             constraint = self._find_foreign_constraints(table_name, column_old)[0]
-            (rtable, rcolumn) = self._lookup_constraint_references(table_name, constraint)
-            if rtable and rcolumn:
+            (ftable, fcolumn) = self._lookup_constraint_references(table_name, constraint)
+            if ftable and fcolumn:
                 fk_sql = self.foreign_key_sql(
-                            table_name, column_new, rtable, rcolumn)
+                            table_name, column_new, ftable, fcolumn)
                 get_logger().debug("Foreign key SQL: " + fk_sql)
                 self.add_deferred_sql(fk_sql)
         except IndexError:
             pass # No constraint exists so ignore
         except DryRunError:
             pass
+        try:
+            reverse = self._lookup_reverse_constraint(table_name, column_old)
+            for cname, rtable, rcolumn in reverse:
+                fk_sql = self.foreign_key_sql(
+                        rtable, rcolumn, table_name, column_new)
+                self.add_deferred_sql(fk_sql)
+        except DryRunError:
+            pass
         return func(self, table_name, column_old, column_new, *args, **opts)
     return _column_cp
 
         try:
             table = self._reverse_cache[db_name][table_name]
             if column_name == None:
-                return table.items()
+                return [(y, tuple(y)) for x, y in table.items()]
             else:
-                return table[column_name]
+                return tuple(table[column_name])
         except KeyError, e:
             return []
 

south/tests/db_mysql.py

         self._create_foreign_tables(main_table, reference_table)
         db.execute_deferred_sql()
         inverse = db._lookup_reverse_constraint(reference_table, 'id')
-        # Hard to extract single value from set, .pop affects cache
-        (cname, rev_table, rev_column) = tuple(inverse)[0]
+        (cname, rev_table, rev_column) = inverse[0]
         self.assertEquals(main_table, rev_table)
         self.assertEquals('foreign_id', rev_column)
         db.delete_table(main_table)
         self.assertEquals(len(constraints), 1)
         db.delete_table(main_table)
         db.delete_table(ref_table)
+
+    def test_rename_fk_inbound(self):
+        """
+        Tests that the column referred to by an external column can be renamed.
+        Edge case, but also useful as stepping stone to renaming tables.
+        """
+        main_table = 'test_rename_fk_inbound'
+        ref_table = 'test_rfi_ref'
+        self._create_foreign_tables(main_table, ref_table)
+        db.execute_deferred_sql()
+        constraints = db._lookup_reverse_constraint(ref_table, 'id')
+        self.assertEquals(len(constraints), 1)
+        db.rename_column(ref_table, 'id', 'rfi_id')
+        db.execute_deferred_sql()  #Create constraints
+        constraints = db._lookup_reverse_constraint(ref_table, 'rfi_id')
+        self.assertEquals(len(constraints), 1)
+        cname = db._find_foreign_constraints(main_table, 'foreign_id')[0]
+        (rtable, rcolumn) = db._lookup_constraint_references(main_table, cname)
+        self.assertEquals('rfi_id', rcolumn)
+        db.delete_table(main_table)
+        db.delete_table(ref_table)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.