Commits

Andrew Godwin committed ecc6fb6

Write some code so, theoretically, things work (i.e. migration runner now uses diff. ORM for backwards(), autodetector ignores short->long field class change)

Comments (0)

Files changed (3)

south/management/commands/startmigration.py

 
 
 # Backwards-compat comparison that ignores orm. on the RHS and not the left
+# and which knows django.db.models.fields.CharField = models.CharField
 def different_attributes(old, new):
     # If they're not triples, just do normal comparison
     if not isinstance(old, (list, tuple)) or not isinstance(new, (list, tuple)):
         return old != new
-    # If the first or third bits or end of second are different, it really is different.
-    if old[0] != new[0] or old[2] != new[2] or old[1][1:] != new[1][1:]:
+    # If the first bit is different, check it's not by dj.db.models...
+    if old[0] != new[0]:
+        if old[0].startswith("models.") and (new[0].startswith("django.db.models") \
+         or new[0].startswith("django.contrib.gis")):
+            return old[0].split(".")[-1] != new[0].split(".")[-1] 
+    # If the third bits or end of second are different, it really is different.
+    if old[2] != new[2] or old[1][1:] != new[1][1:]:
         return True
     if not old[1] and not new[1]:
         return False

south/migration.py

         app_name = get_app_name(app)
         if not silent:
             print toprint % (app_name, migration)
+        
+        # Get migration class
         klass = get_migration(app, migration)
-
+        # Find its predecessor, and attach the ORM from that as prev_orm.
+        all_names = get_migration_names(app)
+        idx = all_names.index(migration)
+        # First migration? The 'previous ORM' is empty.
+        if idx == 0:
+            klass.prev_orm = FakeORM(None, app)
+        else:
+            klass.prev_orm = get_migration(app, all_names[idx-1]).orm
+        
+        # If this is a 'fake' migration, do nothing.
         if fake:
             if not silent:
                 print "   (faked)"
+        
+        # OK, we should probably do something then.
         else:
-            
             runfunc = getattr(klass(), torun)
             args = inspect.getargspec(runfunc)
             
+            # Get the correct ORM.
+            if torun == "forwards":
+                orm = klass.orm
+            else:
+                orm = klass.prev_orm
+            
             # If the database doesn't support running DDL inside a transaction
             # *cough*MySQL*cough* then do a dry run first.
             if not db.has_ddl_transactions or db_dry_run:
                         if len(args[0]) == 1:  # They don't want an ORM param
                             runfunc()
                         else:
-                            runfunc(klass.orm)
+                            runfunc(orm)
                     except:
                         traceback.print_exc()
                         print " ! Error found during dry run of migration! Aborting."
                 if len(args[0]) == 1:  # They don't want an ORM param
                     runfunc()
                 else:
-                    runfunc(klass.orm)
+                    runfunc(orm)
                 db.execute_deferred_sql()
             except:
                 if db.has_ddl_transactions:
                         if len(args[0]) == 1:
                             klass().backwards()
                         else:
-                            klass().backwards(klass.orm)
+                            klass().backwards(klass.prev_orm)
                     print
                     print " ! The South developers regret this has happened, and would"
                     print " ! like to gently persuade you to consider a slightly"

south/modelsinspector.py

 from django.db.models.fields import NOT_PROVIDED
 from django.conf import settings
 
+NOISY = True
+
 # Gives information about how to introspect certain fields.
 # This is a list of triples; the first item is a list of fields it applies to,
 # (note that isinstance is used, so superclasses are perfectly valid here)
     for field in source:
         # Does it define a south_field_triple method?
         if hasattr(field, "south_field_triple"):
-            print "Nativing field: %s" % field.name
+            if NOISY:
+                print "Nativing field: %s" % field.name
             field_defs[field.name] = field.south_field_triple()
         # Can we introspect it?
         elif can_introspect(field):
-            print "Introspecting field: %s" % field.name
+            if NOISY:
+                print "Introspecting field: %s" % field.name
             # Get the full field class path.
             field_class = field.__class__.__module__ + "." + field.__class__.__name__
             # Run this field through the introspector
             field_defs[field.name] = (field_class, args, kwargs)
         # Hmph. Is it parseable?
         elif parser_fields.get(field.name, None):
-            print "Parsing field: %s" % field.name
+            if NOISY:
+                print "Parsing field: %s" % field.name
             field_defs[field.name] = parser_fields[field.name]
         # Shucks, no definition!
         else:
-            print "Nodefing field: %s" % field.name
+            if NOISY:
+                print "Nodefing field: %s" % field.name
             field_defs[field.name] = None
     
     return field_defs