diff --git a/django/db/__init__.py b/django/db/__init__.py
index 8395468..c6f28da 100644
|
a
|
b
|
if DEFAULT_DB_ALIAS not in settings.DATABASES:
|
| 12 | 12 | raise ImproperlyConfigured("You must define a '%s' database" % DEFAULT_DB_ALIAS) |
| 13 | 13 | |
| 14 | 14 | connections = ConnectionHandler(settings.DATABASES) |
| | 15 | connections._ignore_num_queries = False |
| 15 | 16 | |
| 16 | 17 | router = ConnectionRouter(settings.DATABASE_ROUTERS) |
| 17 | 18 | |
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 23ddedb..c9a6d7a 100644
|
a
|
b
|
class BaseDatabaseWrapper(local):
|
| 34 | 34 | self.transaction_state = [] |
| 35 | 35 | self.savepoint_state = 0 |
| 36 | 36 | self._dirty = None |
| | 37 | |
| | 38 | self.constraint_checking_disabled = False |
| 37 | 39 | |
| 38 | 40 | def __eq__(self, other): |
| 39 | 41 | return self.alias == other.alias |
| … |
… |
class BaseDatabaseWrapper(local):
|
| 238 | 240 | """ |
| 239 | 241 | if self.savepoint_state: |
| 240 | 242 | self._savepoint_commit(sid) |
| 241 | | |
| | 243 | |
| 242 | 244 | @contextmanager |
| 243 | 245 | def constraint_checks_disabled(self): |
| 244 | | disabled = self.disable_constraint_checking() |
| | 246 | self.disable_constraint_checking() |
| 245 | 247 | try: |
| 246 | 248 | yield |
| 247 | 249 | finally: |
| 248 | | if disabled: |
| | 250 | if self.constraint_checking_disabled: |
| 249 | 251 | self.enable_constraint_checking() |
| 250 | | |
| | 252 | |
| | 253 | |
| 251 | 254 | def disable_constraint_checking(self): |
| 252 | 255 | """ |
| 253 | 256 | Backends can implement as needed to temporarily disable foreign key constraint |
| 254 | 257 | checking. |
| 255 | 258 | """ |
| 256 | | pass |
| | 259 | self.constraint_checking_disabled = True |
| 257 | 260 | |
| 258 | 261 | def enable_constraint_checking(self): |
| 259 | 262 | """ |
| 260 | 263 | Backends can implement as needed to re-enable foreign key constraint checking. |
| 261 | 264 | """ |
| 262 | | pass |
| 263 | | |
| | 265 | self.constraint_checking_disabled = False |
| | 266 | |
| 264 | 267 | def check_constraints(self, table_names=None): |
| 265 | 268 | """ |
| 266 | 269 | Backends can override this method if they can apply constraint checking (e.g. via "SET CONSTRAINTS |
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 2dd9e84..d6bd824 100644
|
a
|
b
|
class DatabaseWrapper(BaseDatabaseWrapper):
|
| 356 | 356 | to indicate constraint checks need to be re-enabled. |
| 357 | 357 | """ |
| 358 | 358 | self.cursor().execute('SET foreign_key_checks=0') |
| 359 | | return True |
| | 359 | self.constraint_checking_disabled = True |
| 360 | 360 | |
| 361 | 361 | def enable_constraint_checking(self): |
| 362 | 362 | """ |
| 363 | 363 | Re-enable foreign key checks after they have been disabled. |
| 364 | 364 | """ |
| 365 | 365 | self.cursor().execute('SET foreign_key_checks=1') |
| 366 | | |
| | 366 | self.constraint_checking_disabled = False |
| | 367 | |
| 367 | 368 | def check_constraints(self, table_names=None): |
| 368 | 369 | """ |
| 369 | 370 | Checks each table name in `table_names` for rows with invalid foreign key references. This method is |
| … |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
| 389 | 390 | SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING |
| 390 | 391 | LEFT JOIN `%s` as REFERRED |
| 391 | 392 | ON (REFERRING.`%s` = REFERRED.`%s`) |
| 392 | | WHERE REFERRING.`%s` IS NOT NULL AND REFERRED.`%s` IS NULL""" |
| | 393 | WHERE REFERRING.`%s` IS NOT NULL |
| | 394 | AND REFERRED.`%s` IS NULL""" |
| 393 | 395 | % (primary_key_column_name, column_name, table_name, referenced_table_name, |
| 394 | | column_name, referenced_column_name, column_name, referenced_column_name)) |
| | 396 | column_name, referenced_column_name, column_name, referenced_column_name)) |
| 395 | 397 | for bad_row in cursor.fetchall(): |
| 396 | | raise utils.IntegrityError("The row in table '%s' with primary key '%s' has an invalid " |
| 397 | | "foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s." |
| 398 | | % (table_name, bad_row[0], |
| 399 | | table_name, column_name, bad_row[1], |
| 400 | | referenced_table_name, referenced_column_name)) |
| | 398 | raise utils.IntegrityError("The row in table '%s' with primary key '%s' has an invalid \ |
| | 399 | foreign key: %s.%s contains a value '%s' that does not have a corresponding value in %s.%s." |
| | 400 | % (table_name, bad_row[0], table_name, column_name, bad_row[1], |
| | 401 | referenced_table_name, referenced_column_name)) |
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index 37aa072..691c736 100644
|
a
|
b
|
class DatabaseWrapper(BaseDatabaseWrapper):
|
| 105 | 105 | self.introspection = DatabaseIntrospection(self) |
| 106 | 106 | self.validation = BaseDatabaseValidation(self) |
| 107 | 107 | 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') |
| 108 | 116 | |
| 109 | 117 | def check_constraints(self, table_names=None): |
| 110 | 118 | """ |
diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py
index 9652a4d..b1427c0 100644
|
a
|
b
|
class DatabaseIntrospection(BaseDatabaseIntrospection):
|
| 156 | 156 | name = info[0][2] # seqno, cid, name |
| 157 | 157 | indexes[name]['unique'] = True |
| 158 | 158 | 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 |
| 159 | 174 | |
| 160 | 175 | def get_primary_key_column(self, cursor, table_name): |
| 161 | 176 | """ |
diff --git a/django/db/backends/util.py b/django/db/backends/util.py
index 0766f87..e037a5a 100644
|
a
|
b
|
class CursorWrapper(object):
|
| 29 | 29 | class CursorDebugWrapper(CursorWrapper): |
| 30 | 30 | |
| 31 | 31 | def execute(self, sql, params=()): |
| | 32 | from django.db import connections |
| 32 | 33 | start = time() |
| 33 | 34 | try: |
| 34 | 35 | return self.cursor.execute(sql, params) |
| … |
… |
class CursorDebugWrapper(CursorWrapper):
|
| 36 | 37 | stop = time() |
| 37 | 38 | duration = stop - start |
| 38 | 39 | sql = self.db.ops.last_executed_query(self.cursor, sql, params) |
| 39 | | self.db.queries.append({ |
| 40 | | 'sql': sql, |
| 41 | | 'time': "%.3f" % duration, |
| 42 | | }) |
| | 40 | if not connections._ignore_num_queries: |
| | 41 | self.db.queries.append({ |
| | 42 | 'sql': sql, |
| | 43 | 'time': "%.3f" % duration, |
| | 44 | }) |
| 43 | 45 | logger.debug('(%.3f) %s; args=%s' % (duration, sql, params), |
| 44 | 46 | extra={'duration':duration, 'sql':sql, 'params':params} |
| 45 | 47 | ) |
| … |
… |
def format_number(value, max_digits, decimal_places):
|
| 143 | 145 | context.prec = max_digits |
| 144 | 146 | return u'%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)) |
| 145 | 147 | else: |
| 146 | | return u"%.*f" % (decimal_places, value) |
| | 148 | return u"%.*f" % (decimal_places, value) |
| | 149 | No newline at end of file |
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 71687f2..7c50ff5 100644
|
a
|
b
|
from django.utils.encoding import smart_str
|
| 26 | 26 | __all__ = ('DocTestRunner', 'OutputChecker', 'TestCase', 'TransactionTestCase', |
| 27 | 27 | 'SimpleTestCase', 'skipIfDBFeature', 'skipUnlessDBFeature') |
| 28 | 28 | |
| | 29 | |
| | 30 | def ignore_num_queries(fn): |
| | 31 | @wraps(fn) |
| | 32 | def num_queries_ignored(*args, **kwargs): |
| | 33 | connections._ignore_num_queries = True |
| | 34 | try: |
| | 35 | return fn(*args, **kwargs) |
| | 36 | finally: |
| | 37 | connections._ignore_num_queries = False |
| | 38 | return num_queries_ignored |
| | 39 | |
| 29 | 40 | normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) |
| 30 | 41 | normalize_decimals = lambda s: re.sub(r"Decimal\('(\d+(\.\d*)?)'\)", lambda m: "Decimal(\"%s\")" % m.groups()[0], s) |
| 31 | 42 | |
| … |
… |
def to_list(value):
|
| 42 | 53 | |
| 43 | 54 | real_commit = transaction.commit |
| 44 | 55 | real_rollback = transaction.rollback |
| | 56 | real_commit_unless_managed = transaction.commit_unless_managed |
| | 57 | real_rollback_unless_managed = transaction.rollback_unless_managed |
| 45 | 58 | real_enter_transaction_management = transaction.enter_transaction_management |
| 46 | 59 | real_leave_transaction_management = transaction.leave_transaction_management |
| 47 | 60 | real_managed = transaction.managed |
| … |
… |
real_managed = transaction.managed
|
| 49 | 62 | def nop(*args, **kwargs): |
| 50 | 63 | return |
| 51 | 64 | |
| | 65 | @ignore_num_queries |
| | 66 | def check_constraints(using=None): |
| | 67 | """ |
| | 68 | Emulate the constraint check behavior that normally occurs when a transaction is rolled back or committed. |
| | 69 | """ |
| | 70 | if using is None: |
| | 71 | using = DEFAULT_DB_ALIAS |
| | 72 | connection = connections[using] |
| | 73 | # Don't check constraints if they have been manually disabled |
| | 74 | if not connection.constraint_checking_disabled: |
| | 75 | connection.check_constraints() |
| | 76 | |
| 52 | 77 | def disable_transaction_methods(): |
| 53 | | transaction.commit = nop |
| | 78 | transaction.commit = check_constraints |
| 54 | 79 | transaction.rollback = nop |
| | 80 | transaction.commit_unless_managed = check_constraints |
| | 81 | transaction.rollback_unless_managed = nop |
| 55 | 82 | transaction.enter_transaction_management = nop |
| 56 | 83 | transaction.leave_transaction_management = nop |
| 57 | 84 | transaction.managed = nop |
| … |
… |
def disable_transaction_methods():
|
| 59 | 86 | def restore_transaction_methods(): |
| 60 | 87 | transaction.commit = real_commit |
| 61 | 88 | transaction.rollback = real_rollback |
| | 89 | transaction.commit_unless_managed = real_commit_unless_managed |
| | 90 | transaction.rollback_unless_managed = real_rollback_unless_managed |
| 62 | 91 | transaction.enter_transaction_management = real_enter_transaction_management |
| 63 | 92 | transaction.leave_transaction_management = real_leave_transaction_management |
| 64 | 93 | transaction.managed = real_managed |
| … |
… |
class TestCase(TransactionTestCase):
|
| 645 | 674 | |
| 646 | 675 | from django.contrib.sites.models import Site |
| 647 | 676 | Site.objects.clear_cache() |
| | 677 | |
| | 678 | from django.contrib.contenttypes.models import ContentType |
| | 679 | ContentType.objects.clear_cache() |
| 648 | 680 | |
| 649 | 681 | for db in databases: |
| 650 | 682 | if hasattr(self, 'fixtures'): |
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index 27d3dfd..be5d6f4 100644
|
a
|
b
|
class FkConstraintsTests(TransactionTestCase):
|
| 347 | 347 | except IntegrityError: |
| 348 | 348 | return |
| 349 | 349 | self.skipTest("This backend does not support integrity checks.") |
| 350 | | |
| | 350 | |
| 351 | 351 | def test_disable_constraint_checks_manually(self): |
| 352 | 352 | """ |
| 353 | | When constraint checks are disabled, should be able to write bad data without IntegrityErrors. |
| | 353 | When constraint checks are disabled, should be able to write bad data without IntegrityErrors. Also, |
| | 354 | should set disabled flag. |
| 354 | 355 | """ |
| 355 | 356 | with transaction.commit_manually(): |
| 356 | 357 | # Create an Article. |
| … |
… |
class FkConstraintsTests(TransactionTestCase):
|
| 360 | 361 | a.reporter_id = 30 |
| 361 | 362 | try: |
| 362 | 363 | connection.disable_constraint_checking() |
| | 364 | self.assertTrue(connection.constraint_checking_disabled) |
| 363 | 365 | a.save() |
| 364 | 366 | connection.enable_constraint_checking() |
| 365 | 367 | except IntegrityError: |
| 366 | 368 | self.fail("IntegrityError should not have occurred.") |
| 367 | 369 | finally: |
| 368 | 370 | transaction.rollback() |
| 369 | | |
| | 371 | |
| 370 | 372 | def test_disable_constraint_checks_context_manager(self): |
| 371 | 373 | """ |
| 372 | 374 | When constraint checks are disabled (using context manager), should be able to write bad data without IntegrityErrors. |
| … |
… |
class FkConstraintsTests(TransactionTestCase):
|
| 379 | 381 | a.reporter_id = 30 |
| 380 | 382 | try: |
| 381 | 383 | with connection.constraint_checks_disabled(): |
| | 384 | self.assertTrue(connection.constraint_checking_disabled) |
| 382 | 385 | a.save() |
| 383 | 386 | except IntegrityError: |
| 384 | 387 | self.fail("IntegrityError should not have occurred.") |
| 385 | 388 | finally: |
| 386 | 389 | transaction.rollback() |
| 387 | | |
| | 390 | |
| 388 | 391 | def test_check_constraints(self): |
| 389 | 392 | """ |
| 390 | 393 | Constraint checks should raise an IntegrityError when bad data is in the DB. |
diff --git a/tests/regressiontests/comment_tests/tests/templatetag_tests.py b/tests/regressiontests/comment_tests/tests/templatetag_tests.py
index 0ee34ac..835017c 100644
|
a
|
b
|
class CommentTemplateTagTests(CommentTestCase):
|
| 42 | 42 | def testRenderCommentFormFromObjectWithQueryCount(self): |
| 43 | 43 | def test(): |
| 44 | 44 | self.testRenderCommentFormFromObject() |
| 45 | | self.assertNumQueries(1, test) |
| | 45 | # 1 to select object |
| | 46 | # 1 to get the contenttype |
| | 47 | self.assertNumQueries(2, test) |
| 46 | 48 | |
| 47 | 49 | def testGetCommentCount(self, tag=None): |
| 48 | 50 | self.createSomeComments() |
diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py
index 575983b..d72edf3 100644
|
a
|
b
|
class TestFixtures(TestCase):
|
| 361 | 361 | """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]""" |
| 362 | 362 | % widget.pk |
| 363 | 363 | ) |
| | 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 | ) |
| 364 | 393 | |
| 365 | 394 | def test_loaddata_works_when_fixture_has_forward_refs(self): |
| 366 | 395 | """ |
diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py
index 2d5b0a8..8916fdb 100644
|
a
|
b
|
class RouterTestCase(TestCase):
|
| 973 | 973 | # Make the 'other' database appear to be a slave of the 'default' |
| 974 | 974 | self.old_routers = router.routers |
| 975 | 975 | router.routers = [TestRouter()] |
| | 976 | |
| | 977 | # Disable constraint checking, for now |
| | 978 | for connection_name in connections: |
| | 979 | connection = connections[connection_name] |
| | 980 | connection.disable_constraint_checking() |
| 976 | 981 | |
| 977 | 982 | def tearDown(self): |
| 978 | 983 | # Restore the 'other' database as an independent database |
| 979 | 984 | router.routers = self.old_routers |
| | 985 | |
| | 986 | # Re-enable constraint checking |
| | 987 | for connection_name in connections: |
| | 988 | connection = connections[connection_name] |
| | 989 | connection.enable_constraint_checking() |
| 980 | 990 | |
| 981 | 991 | def test_db_selection(self): |
| 982 | 992 | "Check that querysets obey the router for db suggestions" |
| … |
… |
class SignalTests(TestCase):
|
| 1692 | 1702 | |
| 1693 | 1703 | def setUp(self): |
| 1694 | 1704 | self.old_routers = router.routers |
| | 1705 | |
| | 1706 | # Disable constraint checking, for now |
| | 1707 | for connection_name in connections: |
| | 1708 | connection = connections[connection_name] |
| | 1709 | connection.disable_constraint_checking() |
| 1695 | 1710 | |
| 1696 | 1711 | def tearDown(self): |
| 1697 | 1712 | router.routers = self.old_routers |
| | 1713 | |
| | 1714 | # Re-enable constraint checking |
| | 1715 | for connection_name in connections: |
| | 1716 | connection = connections[connection_name] |
| | 1717 | connection.enable_constraint_checking() |
| 1698 | 1718 | |
| 1699 | 1719 | def _write_to_other(self): |
| 1700 | 1720 | "Sends all writes to 'other'." |
diff --git a/tests/regressiontests/test_utils/models.py b/tests/regressiontests/test_utils/models.py
index 4da7a07..7a7a94e 100644
|
a
|
b
|
from django.db import models
|
| 3 | 3 | |
| 4 | 4 | class Person(models.Model): |
| 5 | 5 | name = models.CharField(max_length=100) |
| | 6 | |
| | 7 | class Pet(models.Model): |
| | 8 | name = models.CharField(max_length=100) |
| | 9 | owner = models.ForeignKey(Person) |
| | 10 | |
| | 11 | def __unicode__(self): |
| | 12 | return self.name |
| | 13 | |
| | 14 | class Meta: |
| | 15 | ordering = ('name',) |
diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py
index 942aa85..e2a549a 100644
|
a
|
b
|
|
| 1 | 1 | from __future__ import with_statement |
| 2 | 2 | |
| | 3 | from django.db import IntegrityError |
| 3 | 4 | from django.forms import EmailField |
| 4 | | from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature |
| | 5 | from django.test import TestCase, SimpleTestCase, skipUnlessDBFeature |
| | 6 | from django.test.testcases import ignore_num_queries |
| 5 | 7 | from django.utils.unittest import skip |
| 6 | 8 | |
| 7 | | from models import Person |
| | 9 | |
| | 10 | from models import Person, Pet |
| 8 | 11 | |
| 9 | 12 | |
| 10 | 13 | class SkippingTestCase(TestCase): |
| … |
… |
class AssertNumQueriesTests(TestCase):
|
| 48 | 51 | self.client.get("/test_utils/get_person/%s/" % person.pk) |
| 49 | 52 | self.client.get("/test_utils/get_person/%s/" % person.pk) |
| 50 | 53 | self.assertNumQueries(2, test_func) |
| | 54 | |
| | 55 | def test_assert_num_queries_ignore_decorator(self): |
| | 56 | person = Person.objects.create(name='test') |
| | 57 | |
| | 58 | @ignore_num_queries |
| | 59 | def test_func(): |
| | 60 | self.client.get("/test_utils/get_person/%s/" % person.pk) |
| | 61 | self.client.get("/test_utils/get_person/%s/" % person.pk) |
| | 62 | self.assertNumQueries(0, test_func) |
| 51 | 63 | |
| 52 | 64 | |
| 53 | 65 | class AssertNumQueriesContextManagerTests(TestCase): |
| … |
… |
class AssertNumQueriesContextManagerTests(TestCase):
|
| 88 | 100 | self.client.get("/test_utils/get_person/%s/" % person.pk) |
| 89 | 101 | |
| 90 | 102 | |
| | 103 | class TransactionPatchingTests(TestCase): |
| | 104 | def test_bad_data_should_raise_data_integrity_error(self): |
| | 105 | """ |
| | 106 | Ensure bad data cannot be saved to DB during tests. |
| | 107 | """ |
| | 108 | bill = Person.objects.create(name="Bill") |
| | 109 | dog = Pet.objects.create(name="Spot", owner=bill) |
| | 110 | dog.owner_id = 20 # Does not exist |
| | 111 | with self.assertRaises(IntegrityError): |
| | 112 | dog.save() |
| | 113 | |
| 91 | 114 | class SaveRestoreWarningState(TestCase): |
| 92 | 115 | def test_save_restore_warnings_state(self): |
| 93 | 116 | """ |