Commit 3fc9d7e3 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

[1.2.X] Fixed #14068 -- Corrected error handling in loaddata when an...

[1.2.X] Fixed #14068 -- Corrected error handling in loaddata when an allow_syncdb method is defined on the router. Thanks to Xavier Ordoquy for the report.

Backport of r13612 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@13613 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 1d291ff7
Loading
Loading
Loading
Loading
+18 −9
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ class Command(BaseCommand):

        # Keep a count of the installed objects and fixtures
        fixture_count = 0
        object_count = 0
        loaded_object_count = 0
        fixture_object_count = 0
        models = set()

        humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
@@ -114,7 +115,7 @@ class Command(BaseCommand):
                if verbosity > 1:
                    self.stdout.write("Loading '%s' fixtures...\n" % fixture_name)
            else:
                sys.stderr.write(
                self.stderr.write(
                    self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format.\n" %
                        (fixture_name, format)))
                transaction.rollback(using=using)
@@ -157,17 +158,20 @@ class Command(BaseCommand):
                        else:
                            fixture_count += 1
                            objects_in_fixture = 0
                            loaded_objects_in_fixture = 0
                            if verbosity > 0:
                                self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
                                    (format, fixture_name, humanize(fixture_dir)))
                            try:
                                objects = serializers.deserialize(format, fixture, using=using)
                                for obj in objects:
                                    if router.allow_syncdb(using, obj.object.__class__):
                                    objects_in_fixture += 1
                                    if router.allow_syncdb(using, obj.object.__class__):
                                        loaded_objects_in_fixture += 1
                                        models.add(obj.object.__class__)
                                        obj.save(using=using)
                                object_count += objects_in_fixture
                                loaded_object_count += loaded_objects_in_fixture
                                fixture_object_count += objects_in_fixture
                                label_found = True
                            except (SystemExit, KeyboardInterrupt):
                                raise
@@ -179,7 +183,7 @@ class Command(BaseCommand):
                                if show_traceback:
                                    traceback.print_exc()
                                else:
                                    sys.stderr.write(
                                    self.stderr.write(
                                        self.style.ERROR("Problem installing fixture '%s': %s\n" %
                                             (full_path, ''.join(traceback.format_exception(sys.exc_type,
                                                 sys.exc_value, sys.exc_traceback)))))
@@ -189,7 +193,7 @@ class Command(BaseCommand):
                            # If the fixture we loaded contains 0 objects, assume that an
                            # error was encountered during fixture loading.
                            if objects_in_fixture == 0:
                                sys.stderr.write(
                                self.stderr.write(
                                    self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)\n" %
                                        (fixture_name)))
                                transaction.rollback(using=using)
@@ -203,7 +207,7 @@ class Command(BaseCommand):

        # If we found even one object in a fixture, we need to reset the
        # database sequences.
        if object_count > 0:
        if loaded_object_count > 0:
            sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
            if sequence_sql:
                if verbosity > 1:
@@ -215,12 +219,17 @@ class Command(BaseCommand):
            transaction.commit(using=using)
            transaction.leave_transaction_management(using=using)

        if object_count == 0:
        if fixture_object_count == 0:
            if verbosity > 0:
                self.stdout.write("No fixtures found.\n")
        else:
            if verbosity > 0:
                self.stdout.write("Installed %d object(s) from %d fixture(s)\n" % (object_count, fixture_count))
                if fixture_object_count == loaded_object_count:
                    self.stdout.write("Installed %d object(s) from %d fixture(s)\n" % (
                        loaded_object_count, fixture_count))
                else:
                    self.stdout.write("Installed %d object(s) (of %d) from %d fixture(s)\n" % (
                        loaded_object_count, fixture_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
+18 −0
Original line number Diff line number Diff line
[
    {
        "pk": 1,
        "model": "multiple_database.pet",
        "fields": {
            "name": "Mr Bigglesworth",
            "owner": 1
        }
    },
    {
        "pk": 2,
        "model": "multiple_database.pet",
        "fields": {
            "name": "Spot",
            "owner": 2
        }
    }
]
 No newline at end of file
+28 −0
Original line number Diff line number Diff line
@@ -1569,11 +1569,31 @@ class UserProfileTestCase(TestCase):
        self.assertEquals(alice.get_profile().flavor, 'chocolate')
        self.assertEquals(bob.get_profile().flavor, 'crunchy frog')

class AntiPetRouter(object):
    # A router that only expresses an opinion on syncdb,
    # passing pets to the 'other' database

    def allow_syncdb(self, db, model):
        "Make sure the auth app only appears on the 'other' db"
        if db == 'other':
            return model._meta.object_name == 'Pet'
        else:
            return model._meta.object_name != 'Pet'
        return None

class FixtureTestCase(TestCase):
    multi_db = True
    fixtures = ['multidb-common', 'multidb']

    def setUp(self):
        # Install the anti-pet router
        self.old_routers = router.routers
        router.routers = [AntiPetRouter()]

    def tearDown(self):
        # Restore the 'other' database as an independent database
        router.routers = self.old_routers

    def test_fixture_loading(self):
        "Multi-db fixtures are loaded correctly"
        # Check that "Pro Django" exists on the default database, but not on other database
@@ -1611,6 +1631,14 @@ class FixtureTestCase(TestCase):
        except Book.DoesNotExist:
            self.fail('"The Definitive Guide to Django" should exist on both databases')

    def test_pseudo_empty_fixtures(self):
        "A fixture can contain entries, but lead to nothing in the database; this shouldn't raise an error (ref #14068)"
        new_io = StringIO()
        management.call_command('loaddata', 'pets', stdout=new_io, stderr=new_io)
        command_output = new_io.getvalue().strip()
        # No objects will actually be loaded
        self.assertTrue("Installed 0 object(s) (of 2) from 1 fixture(s)" in command_output)

class PickleQuerySetTestCase(TestCase):
    multi_db = True