Ticket #3615: allow_forward_refs_in_fixtures.diff

File allow_forward_refs_in_fixtures.diff, 7.2 KB (added by Jim Dalton, 10 years ago)

Not there yet, but includes better tests

  • django/db/backends/mysql/base.py

     
    349349                raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
    350350            self.server_version = tuple([int(x) for x in m.groups()])
    351351        return self.server_version
     352
     353    def begin_defer_constraint_checks(self):
     354        self.foreign_key_checks_disabled = True
     355        self.cursor().execute('SET foreign_key_checks=0')
     356
     357    def end_defer_constraint_checks(self):
     358        self.foreign_key_checks_disabled = False
     359        self.cursor().execute('SET foreign_key_checks=1')
  • django/db/backends/__init__.py

     
    3434        self.transaction_state = []
    3535        self.savepoint_state = 0
    3636        self._dirty = None
     37       
     38        self.foreign_key_checks_disabled = False
    3739
    3840    def __eq__(self, other):
    3941        return self.alias == other.alias
     
    239241        if self.savepoint_state:
    240242            self._savepoint_commit(sid)
    241243
     244    def begin_defer_constraint_checks(self):
     245        return None
     246
     247    def end_defer_constraint_checks(self):
     248        return None
     249
    242250    def close(self):
    243251        if self.connection is not None:
    244252            self.connection.close()
  • django/core/management/commands/loaddata.py

     
    88from django.core import serializers
    99from django.core.management.base import BaseCommand
    1010from django.core.management.color import no_style
    11 from django.db import connections, router, transaction, DEFAULT_DB_ALIAS
     11from django.db import connections, router, transaction, DEFAULT_DB_ALIAS, models as db_models
    1212from django.db.models import get_apps
    1313from django.utils.itercompat import product
    1414
     
    161161                            fixture_count += 1
    162162                            objects_in_fixture = 0
    163163                            loaded_objects_in_fixture = 0
     164                            saved_objects = []
    164165                            if verbosity >= 2:
    165166                                self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
    166167                                    (format, fixture_name, humanize(fixture_dir)))
    167168                            try:
    168169                                objects = serializers.deserialize(format, fixture, using=using)
     170                                connection.begin_defer_constraint_checks()
    169171                                for obj in objects:
    170172                                    objects_in_fixture += 1
    171173                                    if router.allow_syncdb(using, obj.object.__class__):
    172174                                        loaded_objects_in_fixture += 1
    173175                                        models.add(obj.object.__class__)
    174176                                        obj.save(using=using)
     177                                        saved_objects.append(obj.object)
     178                                       
     179                                # If we disabled foreign_key_checks, then re-enable them and save them all
     180                                # again. This will expose any referential integrity errors.
     181                                if connection.foreign_key_checks_disabled:
     182                                    connection.end_defer_constraint_checks()
     183                                    for obj in saved_objects:
     184                                        obj.save_base(using=using, raw=True, force_update=True)
     185                                   
    175186                                loaded_object_count += loaded_objects_in_fixture
    176187                                fixture_object_count += objects_in_fixture
    177188                                label_found = True
  • tests/regressiontests/fixtures_regress/fixtures/forward_ref_bad_data.json

     
     1[
     2    {
     3        "pk": 1,
     4        "model": "fixtures_regress.book",
     5        "fields": {
     6            "name": "Cryptonomicon",
     7            "author": 3
     8        }
     9    },
     10    {
     11        "pk": "4",
     12        "model": "fixtures_regress.person",
     13        "fields": {
     14            "name": "Neal Stephenson"
     15        }
     16    }
     17]
     18 No newline at end of file
  • tests/regressiontests/fixtures_regress/fixtures/forward_ref.json

     
     1[
     2    {
     3        "pk": 1,
     4        "model": "fixtures_regress.book",
     5        "fields": {
     6            "name": "Cryptonomicon",
     7            "author": 4
     8        }
     9    },
     10    {
     11        "pk": "4",
     12        "model": "fixtures_regress.person",
     13        "fields": {
     14            "name": "Neal Stephenson"
     15        }
     16    }
     17]
     18 No newline at end of file
  • tests/regressiontests/fixtures_regress/tests.py

     
    1212from django.core.management.commands.dumpdata import sort_dependencies
    1313from django.core.management.base import CommandError
    1414from django.db.models import signals
    15 from django.db import transaction
     15from django.db import transaction, IntegrityError
    1616from django.test import TestCase, TransactionTestCase, skipIfDBFeature, \
    1717    skipUnlessDBFeature
    1818
     
    362362            """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]"""
    363363            % widget.pk
    364364            )
     365   
     366    def test_loaddata_works_when_fixture_has_forward_refs(self):
     367        """
     368        Regression for #3615 - Forward references cause fixtures not to load in MySQL (InnoDB)
     369        """
     370        management.call_command(
     371            'loaddata',
     372            'forward_ref.json',
     373            verbosity=0,
     374            commit=False
     375        )
     376        self.assertEqual(Book.objects.all()[0].id, 1)
     377        self.assertEqual(Person.objects.all()[0].id, 4)
     378   
     379    def test_loaddata_raise_when_fixture_has_forward_refs(self):
     380        """
     381        Regression for #3615 - Ensure data with nonexistent child key references raises error
     382        """
     383        stderr = StringIO()
     384        management.call_command(
     385            'loaddata',
     386            'forward_ref_bad_data.json',
     387            verbosity=0,
     388            commit=False,
     389            stderr=stderr,
     390        )
     391        self.assertTrue(
     392            stderr.getvalue().startswith('Problem installing fixture')
     393        )
    365394
    366395
    367396class NaturalKeyFixtureTests(TestCase):
Back to Top