Ticket #3615: allow_forward_refs_in_fixtures_v9.diff

File allow_forward_refs_in_fixtures_v9.diff, 29.4 KB (added by Jim Dalton, 10 years ago)
  • django/core/management/commands/loaddata.py

    diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
    index 34f3543..0aa07f4 100644
    a b  
     1# This is necessary in Python 2.5 to enable the with statement, in 2.6
     2# and up it is no longer necessary.
     3from __future__ import with_statement
     4
    15import sys
    26import os
    37import gzip
    class Command(BaseCommand): 
    166170                                    (format, fixture_name, humanize(fixture_dir)))
    167171                            try:
    168172                                objects = serializers.deserialize(format, fixture, using=using)
    169                                 for obj in objects:
    170                                     objects_in_fixture += 1
    171                                     if router.allow_syncdb(using, obj.object.__class__):
    172                                         loaded_objects_in_fixture += 1
    173                                         models.add(obj.object.__class__)
    174                                         obj.save(using=using)
     173                               
     174                                with connection.constraint_checks_disabled():
     175                                    for obj in objects:
     176                                        objects_in_fixture += 1
     177                                        if router.allow_syncdb(using, obj.object.__class__):
     178                                            loaded_objects_in_fixture += 1
     179                                            models.add(obj.object.__class__)
     180                                            obj.save(using=using)
     181                                       
     182                                # Since we disabled constraint checks, we must manually check for
     183                                # any invalid keys that might have been added
     184                                table_names = [model._meta.db_table for model in models]
     185                                connection.check_constraints(table_names=table_names)
     186                                   
    175187                                loaded_object_count += loaded_objects_in_fixture
    176188                                fixture_object_count += objects_in_fixture
    177189                                label_found = True
  • django/db/backends/__init__.py

    diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
    index 1c3bc7e..e4f40a8 100644
    a b try: 
    33except ImportError:
    44    import dummy_thread as thread
    55from threading import local
     6from contextlib import contextmanager
    67
    78from django.conf import settings
    89from django.db import DEFAULT_DB_ALIAS
    class BaseDatabaseWrapper(local): 
    237238        """
    238239        if self.savepoint_state:
    239240            self._savepoint_commit(sid)
     241   
     242    @contextmanager
     243    def constraint_checks_disabled(self):
     244        disabled = self.disable_constraint_checking()
     245        try:
     246            yield
     247        finally:
     248            if disabled:
     249                self.enable_constraint_checking()
     250       
     251   
     252    def disable_constraint_checking(self):
     253        """
     254        Backends can implement as needed to temporarily disable foreign key constraint
     255        checking.
     256        """
     257        pass
     258
     259    def enable_constraint_checking(self):
     260        """
     261        Backends can implement as needed to re-enable foreign key constraint checking.
     262        """
     263        pass
     264   
     265    def check_constraints(self, table_names=None):
     266        """
     267        Backends can override this method if they can apply constraint checking (e.g. via "SET CONSTRAINTS
     268        ALL IMMEDIATE"). Should raise an IntegrityError if any invalid foreign key references are encountered.
     269        """
     270        pass
    240271
    241272    def close(self):
    242273        if self.connection is not None:
    class BaseDatabaseIntrospection(object): 
    869900
    870901        return sequence_list
    871902
     903    def get_key_columns(self, cursor, table_name):
     904        """
     905        Backends can override this to return a list of (column_name, referenced_table_name,
     906        referenced_column_name) for all key columns in given table.
     907        """
     908        raise NotImplementedError
     909   
     910    def get_primary_key_column(self, cursor, table_name):
     911        """
     912        Backends can override this to return the column name of the primary key for the given table.
     913        """
     914        raise NotImplementedError
     915
    872916class BaseDatabaseClient(object):
    873917    """
    874918    This class encapsulates all backend-specific methods for opening a
  • django/db/backends/dummy/base.py

    diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py
    index 7de48c8..746f26b 100644
    a b class DatabaseIntrospection(BaseDatabaseIntrospection): 
    3434    get_table_description = complain
    3535    get_relations = complain
    3636    get_indexes = complain
     37    get_key_columns = complain
    3738
    3839class DatabaseWrapper(BaseDatabaseWrapper):
    3940    operators = {}
  • django/db/backends/mysql/base.py

    diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
    index 6d02aa7..fc714da 100644
    a b class DatabaseWrapper(BaseDatabaseWrapper): 
    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 disable_constraint_checking(self):
     354        """
     355        Disables foreign key checks, primarily for use in adding rows with forward references. Always returns True,
     356        to indicate constraint checks need to be re-enabled.
     357        """
     358        self.cursor().execute('SET foreign_key_checks=0')
     359        return True
     360
     361    def enable_constraint_checking(self):
     362        """
     363        Re-enable foreign key checks after they have been disabled.
     364        """
     365        self.cursor().execute('SET foreign_key_checks=1')
     366   
     367    def check_constraints(self, table_names=None):
     368        """
     369        Checks each table name in table-names for rows with invalid foreign key references. This method is
     370        intended to be used in conjunction with `disable_constraint_checking()` and `enable_constraint_checking()`, to
     371        determine if rows with invalid references were entered while constraint checks were off.
     372
     373        Raises an IntegrityError on the first invalid foreign key reference encountered (if any) and provides
     374        detailed information about the invalid reference in the error message.
     375
     376        Backends can override this method if they can more directly apply constraint checking (e.g. via "SET CONSTRAINTS
     377        ALL IMMEDIATE")
     378        """
     379        cursor = self.cursor()
     380        if table_names is None:
     381            table_names = self.introspection.get_table_list(cursor)
     382        for table_name in table_names:
     383            primary_key_column_name = self.introspection.get_primary_key_column(cursor, table_name)
     384            if not primary_key_column_name:
     385                continue
     386            key_columns = self.introspection.get_key_columns(cursor, table_name)
     387            for column_name, referenced_table_name, referenced_column_name in key_columns:
     388                cursor.execute("""
     389                    SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING
     390                    LEFT JOIN `%s` as REFERRED
     391                    ON (REFERRING.`%s` = REFERRED.`%s`)
     392                    WHERE REFERRING.`%s` IS NOT NULL
     393                        AND REFERRED.`%s` IS NULL"""
     394                    % (primary_key_column_name, column_name, table_name, referenced_table_name,
     395                       column_name, referenced_column_name, column_name, referenced_column_name))
     396                for bad_row in cursor.fetchall():
     397                    raise utils.IntegrityError("The row in table '%s' with primary key '%s' has an invalid \
     398foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s."
     399                                         % (table_name, bad_row[0], table_name, column_name, bad_row[1],
     400                                            referenced_table_name, referenced_column_name))
  • django/db/backends/mysql/introspection.py

    diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py
    index 9e1518b..4612221 100644
    a b class DatabaseIntrospection(BaseDatabaseIntrospection): 
    5151        representing all relationships to the given table. Indexes are 0-based.
    5252        """
    5353        my_field_dict = self._name_to_index(cursor, table_name)
    54         constraints = []
     54        constraints = self.get_key_columns(cursor, table_name)
    5555        relations = {}
     56        for my_fieldname, other_table, other_field in constraints:
     57            other_field_index = self._name_to_index(cursor, other_table)[other_field]
     58            my_field_index = my_field_dict[my_fieldname]
     59            relations[my_field_index] = (other_field_index, other_table)
     60        return relations
     61
     62    def get_key_columns(self, cursor, table_name):
     63        """
     64        Returns a list of (column_name, referenced_table_name, referenced_column_name) for all
     65        key columns in given table.
     66        """
     67        key_columns = []
    5668        try:
    57             # This should work for MySQL 5.0.
    5869            cursor.execute("""
    5970                SELECT column_name, referenced_table_name, referenced_column_name
    6071                FROM information_schema.key_column_usage
    class DatabaseIntrospection(BaseDatabaseIntrospection): 
    6273                    AND table_schema = DATABASE()
    6374                    AND referenced_table_name IS NOT NULL
    6475                    AND referenced_column_name IS NOT NULL""", [table_name])
    65             constraints.extend(cursor.fetchall())
     76            key_columns.extend(cursor.fetchall())
    6677        except (ProgrammingError, OperationalError):
    6778            # Fall back to "SHOW CREATE TABLE", for previous MySQL versions.
    6879            # Go through all constraints and save the equal matches.
    class DatabaseIntrospection(BaseDatabaseIntrospection): 
    7485                    if match == None:
    7586                        break
    7687                    pos = match.end()
    77                     constraints.append(match.groups())
    78 
    79         for my_fieldname, other_table, other_field in constraints:
    80             other_field_index = self._name_to_index(cursor, other_table)[other_field]
    81             my_field_index = my_field_dict[my_fieldname]
    82             relations[my_field_index] = (other_field_index, other_table)
    83 
    84         return relations
     88                    key_columns.append(match.groups())
     89        return key_columns
     90   
     91    def get_primary_key_column(self, cursor, table_name):
     92        """
     93        Returns the name of the primary key column for the given table
     94        """
     95        for column in self.get_indexes(cursor, table_name).iteritems():
     96            if column[1]['primary_key']:
     97                return column[0]
     98        return None
    8599
    86100    def get_indexes(self, cursor, table_name):
    87101        """
  • django/db/backends/oracle/base.py

    diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
    index 930b1bb..3cadb66 100644
    a b class DatabaseWrapper(BaseDatabaseWrapper): 
    428428        self.introspection = DatabaseIntrospection(self)
    429429        self.validation = BaseDatabaseValidation(self)
    430430
     431    def check_constraints(self, table_names=None):
     432        """
     433        To check constraints, we set constraints to immediate. Then, when, we're done we must ensure they
     434        are returned to deferred.
     435        """
     436        self.cursor().execute('SET CONSTRAINTS ALL IMMEDIATE')
     437        self.cursor().execute('SET CONSTRAINTS ALL DEFERRED')
     438
    431439    def _valid_connection(self):
    432440        return self.connection is not None
    433441
  • django/db/backends/postgresql_psycopg2/base.py

    diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
    index 6ed59a6..4136d4f 100644
    a b class DatabaseWrapper(BaseDatabaseWrapper): 
    105105        self.introspection = DatabaseIntrospection(self)
    106106        self.validation = BaseDatabaseValidation(self)
    107107        self._pg_version = None
     108   
     109    def check_constraints(self, table_names=None):
     110        """
     111        To check constraints, we set constraints to immediate. Then, when, we're done we must ensure they
     112        are returned to deferred.
     113        """
     114        self.cursor().execute('SET CONSTRAINTS ALL IMMEDIATE')
     115        self.cursor().execute('SET CONSTRAINTS ALL DEFERRED')
    108116
    109117    def _get_pg_version(self):
    110118        if self._pg_version is None:
  • django/db/backends/sqlite3/base.py

    diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
    index 79c5ede..bc16d9a 100644
    a b class DatabaseWrapper(BaseDatabaseWrapper): 
    206206            connection_created.send(sender=self.__class__, connection=self)
    207207        return self.connection.cursor(factory=SQLiteCursorWrapper)
    208208
     209    def check_constraints(self, table_names=None):
     210        """
     211        Checks each table name in table-names for rows with invalid foreign key references. This method is
     212        intended to be used in conjunction with `disable_constraint_checking()` and `enable_constraint_checking()`, to
     213        determine if rows with invalid references were entered while constraint checks were off.
     214
     215        Raises an IntegrityError on the first invalid foreign key reference encountered (if any) and provides
     216        detailed information about the invalid reference in the error message.
     217
     218        Backends can override this method if they can more directly apply constraint checking (e.g. via "SET CONSTRAINTS
     219        ALL IMMEDIATE")
     220        """
     221        cursor = self.cursor()
     222        if table_names is None:
     223            table_names = self.introspection.get_table_list(cursor)
     224        for table_name in table_names:
     225            primary_key_column_name = self.introspection.get_primary_key_column(cursor, table_name)
     226            if not primary_key_column_name:
     227                continue
     228            key_columns = self.introspection.get_key_columns(cursor, table_name)
     229            for column_name, referenced_table_name, referenced_column_name in key_columns:
     230                cursor.execute("""
     231                    SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING
     232                    LEFT JOIN `%s` as REFERRED
     233                    ON (REFERRING.`%s` = REFERRED.`%s`)
     234                    WHERE REFERRING.`%s` IS NOT NULL
     235                        AND REFERRED.`%s` IS NULL"""
     236                    % (primary_key_column_name, column_name, table_name, referenced_table_name,
     237                       column_name, referenced_column_name, column_name, referenced_column_name))
     238                for bad_row in cursor.fetchall():
     239                    raise utils.IntegrityError("The row in table '%s' with primary key '%s' has an invalid \
     240foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s."
     241                                         % (table_name, bad_row[0], table_name, column_name, bad_row[1],
     242                                            referenced_table_name, referenced_column_name))
     243
    209244    def close(self):
    210245        # If database is in memory, closing the connection destroys the
    211246        # database. To prevent accidental data loss, ignore close requests on
  • django/db/backends/sqlite3/introspection.py

    diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py
    index 5ee7b64..27de913 100644
    a b class DatabaseIntrospection(BaseDatabaseIntrospection): 
    103103
    104104        return relations
    105105
     106    def get_key_columns(self, cursor, table_name):
     107        """
     108        Returns a list of (column_name, referenced_table_name, referenced_column_name) for all
     109        key columns in given table.
     110        """
     111        key_columns = []
     112
     113        # Schema for this table
     114        cursor.execute("SELECT sql FROM sqlite_master WHERE tbl_name = %s AND type = %s", [table_name, "table"])
     115        results = cursor.fetchone()[0].strip()
     116        results = results[results.index('(')+1:results.rindex(')')]
     117
     118        # Walk through and look for references to other tables. SQLite doesn't
     119        # really have enforced references, but since it echoes out the SQL used
     120        # to create the table we can look for REFERENCES statements used there.
     121        for field_index, field_desc in enumerate(results.split(',')):
     122            field_desc = field_desc.strip()
     123            if field_desc.startswith("UNIQUE"):
     124                continue
     125
     126            m = re.search('"(.*)".*references (.*) \(["|](.*)["|]\)', field_desc, re.I)
     127            if not m:
     128                continue
     129
     130            # This will append (column_name, referenced_table_name, referenced_column_name) to key_columns
     131            key_columns.append(tuple([s.strip('"') for s in m.groups()]))
     132
     133        return key_columns
     134       
    106135    def get_indexes(self, cursor, table_name):
    107136        """
    108137        Returns a dictionary of fieldname -> infodict for the given table,
    class DatabaseIntrospection(BaseDatabaseIntrospection): 
    127156            name = info[0][2] # seqno, cid, name
    128157            indexes[name]['unique'] = True
    129158        return indexes
     159   
     160    def get_primary_key_column(self, cursor, table_name):
     161        """
     162        Get the column name of the primary key for the given table.
     163        """
     164        # Don't use PRAGMA because that causes issues with some transactions
     165        cursor.execute("SELECT sql FROM sqlite_master WHERE tbl_name = %s AND type = %s", [table_name, "table"])
     166        results = cursor.fetchone()[0].strip()
     167        results = results[results.index('(')+1:results.rindex(')')]
     168        for field_desc in results.split(','):
     169            field_desc = field_desc.strip()
     170            m = re.search('"(.*)".*PRIMARY KEY$', field_desc)
     171            if m:
     172                return m.groups()[0]
     173        return None
    130174
    131175    def _table_info(self, cursor, name):
    132176        cursor.execute('PRAGMA table_info(%s)' % self.connection.ops.quote_name(name))
  • docs/ref/databases.txt

    diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
    index 2f55b9c..5a2042a 100644
    a b currently the only engine that supports full-text indexing and searching. 
    142142The InnoDB_ engine is fully transactional and supports foreign key references
    143143and is probably the best choice at this point in time.
    144144
     145.. versionchanged:: 1.4
     146
     147In previous versions of Django, fixtures with forward references (i.e.
     148relations to rows that have not yet been inserted into the database) would fail
     149to load when using the InnoDB storage engine. This was due to the fact that InnoDB
     150deviates from the SQL standard by checking foreign key constraints immediately
     151instead of deferring the check until the transaction is committed. This
     152problem has been resolved in Django 1.4. Fixture data is now loaded with foreign key
     153checks turned off; foreign key checks are then re-enabled when the data has
     154finished loading, at which point the entire table is checked for invalid foreign
     155key references and an `IntegrityError` is raised if any are found.
     156
    145157.. _storage engines: http://dev.mysql.com/doc/refman/5.5/en/storage-engines.html
    146158.. _MyISAM: http://dev.mysql.com/doc/refman/5.5/en/myisam-storage-engine.html
    147159.. _InnoDB: http://dev.mysql.com/doc/refman/5.5/en/innodb.html
  • tests/modeltests/serializers/tests.py

    diff --git a/tests/modeltests/serializers/tests.py b/tests/modeltests/serializers/tests.py
    index 4a7e0a2..def0254 100644
    a b  
     1# This is necessary in Python 2.5 to enable the with statement, in 2.6
     2# and up it is no longer necessary.
     3from __future__ import with_statement
     4
    15# -*- coding: utf-8 -*-
    26from datetime import datetime
    37from StringIO import StringIO
    from xml.dom import minidom 
    59
    610from django.conf import settings
    711from django.core import serializers
    8 from django.db import transaction
     12from django.db import transaction, connection
    913from django.test import TestCase, TransactionTestCase, Approximate
    1014from django.utils import simplejson, unittest
    1115
    class SerializersTransactionTestBase(object): 
    252256        transaction.enter_transaction_management()
    253257        transaction.managed(True)
    254258        objs = serializers.deserialize(self.serializer_name, self.fwd_ref_str)
    255         for obj in objs:
    256             obj.save()
     259        with connection.constraint_checks_disabled():
     260            for obj in objs:
     261                obj.save()
    257262        transaction.commit()
    258263        transaction.leave_transaction_management()
    259264
  • tests/regressiontests/backends/tests.py

    diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
    index 29db6a7..8adb40f 100644
    a b  
    11# -*- coding: utf-8 -*-
    22# Unit and doctests for specific database backends.
     3from __future__ import with_statement
    34import datetime
    45
    56from django.conf import settings
    67from django.core.management.color import no_style
    7 from django.db import backend, connection, connections, DEFAULT_DB_ALIAS, IntegrityError
     8from django.db import backend, connection, connections, DEFAULT_DB_ALIAS, IntegrityError, transaction
    89from django.db.backends.signals import connection_created
    910from django.db.backends.postgresql_psycopg2 import version as pg_version
    1011from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
    class FkConstraintsTests(TransactionTestCase): 
    328329        try:
    329330            a.save()
    330331        except IntegrityError:
    331             pass
     332            return
     333        self.skipTest("This backend does not support integrity checks.")
    332334
    333335    def test_integrity_checks_on_update(self):
    334336        """
    class FkConstraintsTests(TransactionTestCase): 
    343345        try:
    344346            a.save()
    345347        except IntegrityError:
    346             pass
     348            return
     349        self.skipTest("This backend does not support integrity checks.")
     350   
     351    def test_disable_constraint_checks_manually(self):
     352        """
     353        When constraint checks are disabled, should be able to write bad data without IntegrityErrors.
     354        """
     355        with transaction.commit_manually():
     356            # Create an Article.
     357            models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
     358            # Retrive it from the DB
     359            a = models.Article.objects.get(headline="Test article")
     360            a.reporter_id = 30
     361            try:
     362                connection.disable_constraint_checking()
     363                a.save()
     364                connection.enable_constraint_checking()
     365            except IntegrityError:
     366                self.fail("IntegrityError should not have occurred.")
     367            finally:
     368                transaction.rollback()
     369   
     370    def test_disable_constraint_checks_context_manager(self):
     371        """
     372        When constraint checks are disabled (using context manager), should be able to write bad data without IntegrityErrors.
     373        """
     374        with transaction.commit_manually():
     375            # Create an Article.
     376            models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
     377            # Retrive it from the DB
     378            a = models.Article.objects.get(headline="Test article")
     379            a.reporter_id = 30
     380            try:
     381                with connection.constraint_checks_disabled():
     382                    a.save()
     383            except IntegrityError:
     384                self.fail("IntegrityError should not have occurred.")
     385            finally:
     386                transaction.rollback()
     387   
     388    def test_check_constraints(self):
     389        """
     390        Constraint checks should raise an IntegrityError when bad data is in the DB.
     391        """
     392        with transaction.commit_manually():
     393            # Create an Article.
     394            models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
     395            # Retrive it from the DB
     396            a = models.Article.objects.get(headline="Test article")
     397            a.reporter_id = 30
     398            try:
     399                with connection.constraint_checks_disabled():
     400                    a.save()
     401                    with self.assertRaises(IntegrityError):
     402                        connection.check_constraints()
     403            finally:
     404                transaction.rollback()
  • new file tests/regressiontests/fixtures_regress/fixtures/forward_ref.json

    diff --git a/tests/regressiontests/fixtures_regress/fixtures/forward_ref.json b/tests/regressiontests/fixtures_regress/fixtures/forward_ref.json
    new file mode 100644
    index 0000000..237b076
    - +  
     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
  • new file tests/regressiontests/fixtures_regress/fixtures/forward_ref_bad_data.json

    diff --git a/tests/regressiontests/fixtures_regress/fixtures/forward_ref_bad_data.json b/tests/regressiontests/fixtures_regress/fixtures/forward_ref_bad_data.json
    new file mode 100644
    index 0000000..3a3fb64
    - +  
     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/tests.py

    diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py
    index a565ec9..344bc04 100644
    a b class TestFixtures(TestCase): 
    361361            """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]"""
    362362            % widget.pk
    363363            )
     364   
     365    def test_loaddata_works_when_fixture_has_forward_refs(self):
     366        """
     367        Regression for #3615 - Forward references cause fixtures not to load in MySQL (InnoDB)
     368        """
     369        management.call_command(
     370            'loaddata',
     371            'forward_ref.json',
     372            verbosity=0,
     373            commit=False
     374        )
     375        self.assertEqual(Book.objects.all()[0].id, 1)
     376        self.assertEqual(Person.objects.all()[0].id, 4)
     377   
     378    def test_loaddata_raises_error_when_fixture_has_invalid_foreign_key(self):
     379        """
     380        Regression for #3615 - Ensure data with nonexistent child key references raises error
     381        """
     382        stderr = StringIO()
     383        management.call_command(
     384            'loaddata',
     385            'forward_ref_bad_data.json',
     386            verbosity=0,
     387            commit=False,
     388            stderr=stderr,
     389        )
     390        self.assertTrue(
     391            stderr.getvalue().startswith('Problem installing fixture')
     392        )
    364393
    365394
    366395class NaturalKeyFixtureTests(TestCase):
  • tests/regressiontests/introspection/tests.py

    diff --git a/tests/regressiontests/introspection/tests.py b/tests/regressiontests/introspection/tests.py
    index 4f5fb09..a7c5bf2 100644
    a b class IntrospectionTests(TestCase): 
    9595            # That's {field_index: (field_index_other_table, other_table)}
    9696            self.assertEqual(relations, {3: (0, Reporter._meta.db_table)})
    9797
     98    def test_get_key_columns(self):
     99        cursor = connection.cursor()
     100        key_columns = connection.introspection.get_key_columns(cursor, Article._meta.db_table)
     101        self.assertEqual(key_columns, [(u'reporter_id', Reporter._meta.db_table, u'id')])
     102   
     103    def test_get_primary_key_column(self):
     104        cursor = connection.cursor()
     105        primary_key_column = connection.introspection.get_primary_key_column(cursor, Article._meta.db_table)
     106        self.assertEqual(primary_key_column, u'id')
     107
    98108    def test_get_indexes(self):
    99109        cursor = connection.cursor()
    100110        indexes = connection.introspection.get_indexes(cursor, Article._meta.db_table)
  • tests/regressiontests/serializers_regress/tests.py

    diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py
    index cd2ce3c..bb6f598 100644
    a b test case that is capable of testing the capabilities of 
    66the serializers. This includes all valid data values, plus
    77forward, backwards and self references.
    88"""
     9# This is necessary in Python 2.5 to enable the with statement, in 2.6
     10# and up it is no longer necessary.
    911from __future__ import with_statement
    1012
    1113import datetime
    def serializerTest(format, self): 
    382384    objects = []
    383385    instance_count = {}
    384386    for (func, pk, klass, datum) in test_data:
    385         objects.extend(func[0](pk, klass, datum))
     387        with connection.constraint_checks_disabled():
     388            objects.extend(func[0](pk, klass, datum))
    386389
    387390    # Get a count of the number of objects created for each class
    388391    for klass in instance_count:
Back to Top