app/django/core/management/commands/loaddata.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
--- a/app/django/core/management/commands/loaddata.py	Tue Oct 14 12:36:55 2008 +0000
+++ b/app/django/core/management/commands/loaddata.py	Tue Oct 14 16:00:59 2008 +0000
@@ -10,11 +10,6 @@
     from sets import Set as set   # Python 2.3 fallback
 
 class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('--verbosity', action='store', dest='verbosity', default='1',
-            type='choice', choices=['0', '1', '2'],
-            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
-    )
     help = 'Installs the named fixture(s) in the database.'
     args = "fixture [fixture ...]"
 
@@ -29,9 +24,18 @@
         verbosity = int(options.get('verbosity', 1))
         show_traceback = options.get('traceback', False)
 
+        # commit is a stealth option - it isn't really useful as
+        # a command line option, but it can be useful when invoking
+        # loaddata from within another script.
+        # If commit=True, loaddata will use its own transaction;
+        # if commit=False, the data load SQL will become part of
+        # the transaction in place when loaddata was invoked.
+        commit = options.get('commit', True)
+
         # Keep a count of the installed objects and fixtures
         fixture_count = 0
         object_count = 0
+        objects_per_fixture = []
         models = set()
 
         humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
@@ -43,9 +47,10 @@
 
         # Start transaction management. All fixtures are installed in a
         # single transaction to ensure that all references are resolved.
-        transaction.commit_unless_managed()
-        transaction.enter_transaction_management()
-        transaction.managed(True)
+        if commit:
+            transaction.commit_unless_managed()
+            transaction.enter_transaction_management()
+            transaction.managed(True)
 
         app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()]
         for fixture_label in fixture_labels:
@@ -60,11 +65,16 @@
                 else:
                     formats = []
 
-            if verbosity >= 2:
-                if formats:
+            if formats:
+                if verbosity > 1:
                     print "Loading '%s' fixtures..." % fixture_name
-                else:
-                    print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
+            else:
+                sys.stderr.write(
+                    self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format." %
+                        (fixture_name, format)))
+                transaction.rollback()
+                transaction.leave_transaction_management()
+                return
 
             if os.path.isabs(fixture_name):
                 fixture_dirs = [fixture_name]
@@ -93,6 +103,7 @@
                             return
                         else:
                             fixture_count += 1
+                            objects_per_fixture.append(0)
                             if verbosity > 0:
                                 print "Installing %s fixture '%s' from %s." % \
                                     (format, fixture_name, humanize(fixture_dir))
@@ -100,10 +111,14 @@
                                 objects = serializers.deserialize(format, fixture)
                                 for obj in objects:
                                     object_count += 1
+                                    objects_per_fixture[-1] += 1
                                     models.add(obj.object.__class__)
                                     obj.save()
                                 label_found = True
-                            except Exception, e:
+                            except (SystemExit, KeyboardInterrupt):
+                                raise
+                            except Exception:
+                                import traceback
                                 fixture.close()
                                 transaction.rollback()
                                 transaction.leave_transaction_management()
@@ -113,14 +128,27 @@
                                 else:
                                     sys.stderr.write(
                                         self.style.ERROR("Problem installing fixture '%s': %s\n" %
-                                             (full_path, str(e))))
+                                             (full_path, traceback.format_exc())))
                                 return
                             fixture.close()
                     except:
-                        if verbosity >= 2:
+                        if verbosity > 1:
                             print "No %s fixture '%s' in %s." % \
                                 (format, fixture_name, humanize(fixture_dir))
 
+
+        # If any of the fixtures we loaded contain 0 objects, assume that an
+        # error was encountered during fixture loading.
+        if 0 in objects_per_fixture:
+            sys.stderr.write(
+                self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" %
+                    (fixture_name)))
+            transaction.rollback()
+            transaction.leave_transaction_management()
+            return
+
+        # If we found even one object in a fixture, we need to reset the
+        # database sequences.
         if object_count > 0:
             sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
             if sequence_sql:
@@ -129,12 +157,20 @@
                 for line in sequence_sql:
                     cursor.execute(line)
 
-        transaction.commit()
-        transaction.leave_transaction_management()
+        if commit:
+            transaction.commit()
+            transaction.leave_transaction_management()
 
         if object_count == 0:
-            if verbosity >= 2:
+            if verbosity > 1:
                 print "No fixtures found."
         else:
             if verbosity > 0:
                 print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)
+
+        # Close the DB connection. This is required as a workaround for an
+        # edge case in MySQL: if the same connection is used to
+        # create tables, load data, and query, the query can return
+        # incorrect results. See Django #7572, MySQL #37735.
+        if commit:
+            connection.close()