Fixed #17530 - Fixture loading with deferred constraints broken for Postgres for fixtures from multiple dirs/files

Thanks to claudep for the review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17372 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2012-01-14 17:26:32 +00:00
parent 64229eb388
commit 4e29b70b9d
4 changed files with 152 additions and 109 deletions

View File

@ -104,6 +104,9 @@ class Command(BaseCommand):
app_module_paths.append(app.__file__) app_module_paths.append(app.__file__)
app_fixtures = [os.path.join(os.path.dirname(path), 'fixtures') for path in app_module_paths] app_fixtures = [os.path.join(os.path.dirname(path), 'fixtures') for path in app_module_paths]
try:
with connection.constraint_checks_disabled():
for fixture_label in fixture_labels: for fixture_label in fixture_labels:
parts = fixture_label.split('.') parts = fixture_label.split('.')
@ -166,25 +169,24 @@ class Command(BaseCommand):
self.stdout.write("No %s fixture '%s' in %s.\n" % \ self.stdout.write("No %s fixture '%s' in %s.\n" % \
(format, fixture_name, humanize(fixture_dir))) (format, fixture_name, humanize(fixture_dir)))
else: else:
try:
if label_found: if label_found:
fixture.close()
self.stderr.write(self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting.\n" % self.stderr.write(self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting.\n" %
(fixture_name, humanize(fixture_dir)))) (fixture_name, humanize(fixture_dir))))
if commit: if commit:
transaction.rollback(using=using) transaction.rollback(using=using)
transaction.leave_transaction_management(using=using) transaction.leave_transaction_management(using=using)
return return
else:
fixture_count += 1 fixture_count += 1
objects_in_fixture = 0 objects_in_fixture = 0
loaded_objects_in_fixture = 0 loaded_objects_in_fixture = 0
if verbosity >= 2: if verbosity >= 2:
self.stdout.write("Installing %s fixture '%s' from %s.\n" % \ self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
(format, fixture_name, humanize(fixture_dir))) (format, fixture_name, humanize(fixture_dir)))
try:
objects = serializers.deserialize(format, fixture, using=using) objects = serializers.deserialize(format, fixture, using=using)
with connection.constraint_checks_disabled():
for obj in objects: for obj in objects:
objects_in_fixture += 1 objects_in_fixture += 1
if router.allow_syncdb(using, obj.object.__class__): if router.allow_syncdb(using, obj.object.__class__):
@ -201,29 +203,10 @@ class Command(BaseCommand):
} }
raise e.__class__, e.__class__(msg), sys.exc_info()[2] raise e.__class__, e.__class__(msg), sys.exc_info()[2]
# Since we disabled constraint checks, we must manually check for
# any invalid keys that might have been added
table_names = [model._meta.db_table for model in models]
connection.check_constraints(table_names=table_names)
loaded_object_count += loaded_objects_in_fixture loaded_object_count += loaded_objects_in_fixture
fixture_object_count += objects_in_fixture fixture_object_count += objects_in_fixture
label_found = True label_found = True
except (SystemExit, KeyboardInterrupt): finally:
raise
except Exception:
fixture.close()
if commit:
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
if show_traceback:
traceback.print_exc()
else:
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)))))
return
fixture.close() fixture.close()
# If the fixture we loaded contains 0 objects, assume that an # If the fixture we loaded contains 0 objects, assume that an
@ -237,6 +220,27 @@ class Command(BaseCommand):
transaction.leave_transaction_management(using=using) transaction.leave_transaction_management(using=using)
return return
# Since we disabled constraint checks, we must manually check for
# any invalid keys that might have been added
table_names = [model._meta.db_table for model in models]
connection.check_constraints(table_names=table_names)
except (SystemExit, KeyboardInterrupt):
raise
except Exception:
if commit:
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
if show_traceback:
traceback.print_exc()
else:
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)))))
return
# If we found even one object in a fixture, we need to reset the # If we found even one object in a fixture, we need to reset the
# database sequences. # database sequences.
if loaded_object_count > 0: if loaded_object_count > 0:

View File

@ -0,0 +1,10 @@
[
{
"pk": 1,
"model": "fixtures_regress.book",
"fields": {
"name": "Cryptonomicon",
"author": 4
}
}
]

View File

@ -0,0 +1,9 @@
[
{
"pk": "4",
"model": "fixtures_regress.person",
"fields": {
"name": "Neal Stephenson"
}
}
]

View File

@ -16,6 +16,7 @@ from django.db import transaction
from django.db.models import signals from django.db.models import signals
from django.test import (TestCase, TransactionTestCase, skipIfDBFeature, from django.test import (TestCase, TransactionTestCase, skipIfDBFeature,
skipUnlessDBFeature) skipUnlessDBFeature)
from django.test.utils import override_settings
from .models import (Animal, Stuff, Absolute, Parent, Child, Article, Widget, from .models import (Animal, Stuff, Absolute, Parent, Child, Article, Widget,
Store, Person, Book, NKChild, RefToNKChild, Circle1, Circle2, Circle3, Store, Person, Book, NKChild, RefToNKChild, Circle1, Circle2, Circle3,
@ -390,6 +391,25 @@ class TestFixtures(TestCase):
stderr.getvalue().startswith('Problem installing fixture') stderr.getvalue().startswith('Problem installing fixture')
) )
_cur_dir = os.path.dirname(os.path.abspath(__file__))
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
os.path.join(_cur_dir, 'fixtures_2')])
def test_loaddata_forward_refs_split_fixtures(self):
"""
Regression for #17530 - should be able to cope with forward references
when the fixtures are not in the same files or directories.
"""
management.call_command(
'loaddata',
'forward_ref_1.json',
'forward_ref_2.json',
verbosity=0,
commit=False
)
self.assertEqual(Book.objects.all()[0].id, 1)
self.assertEqual(Person.objects.all()[0].id, 4)
def test_loaddata_no_fixture_specified(self): def test_loaddata_no_fixture_specified(self):
""" """
Regression for #7043 - Error is quickly reported when no fixtures is provided in the command line. Regression for #7043 - Error is quickly reported when no fixtures is provided in the command line.