diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
|
a
|
b
|
|
| 255 | 255 | def make_debug_cursor(self, cursor): |
| 256 | 256 | return util.CursorDebugWrapper(cursor, self) |
| 257 | 257 | |
| | 258 | def check_constraints(self): |
| | 259 | sql = self.ops.check_constraints_sql() |
| | 260 | for s in sql: |
| | 261 | self.cursor().execute(s) |
| | 262 | |
| 258 | 263 | class BaseDatabaseFeatures(object): |
| 259 | 264 | allows_group_by_pk = False |
| 260 | 265 | # True if django.db.backend.utils.typecast_timestamp is used on values |
| … |
… |
|
| 440 | 445 | """ |
| 441 | 446 | return '' |
| 442 | 447 | |
| | 448 | def check_constraints_sql(self): |
| | 449 | """ |
| | 450 | Returns the SQL necessary to force deferred constraints to be checked. |
| | 451 | """ |
| | 452 | return [] |
| | 453 | |
| 443 | 454 | def drop_foreignkey_sql(self): |
| 444 | 455 | """ |
| 445 | 456 | Returns the SQL command that drops a foreign key. |
diff --git a/django/db/backends/postgresql_psycopg2/operations.py b/django/db/backends/postgresql_psycopg2/operations.py
|
a
|
b
|
|
| 39 | 39 | def deferrable_sql(self): |
| 40 | 40 | return " DEFERRABLE INITIALLY DEFERRED" |
| 41 | 41 | |
| | 42 | def check_constraints_sql(self): |
| | 43 | return ["SET CONSTRAINTS ALL IMMEDIATE"] |
| | 44 | |
| 42 | 45 | def lookup_cast(self, lookup_type): |
| 43 | 46 | lookup = '%s' |
| 44 | 47 | |
diff --git a/django/test/testcases.py b/django/test/testcases.py
|
a
|
b
|
|
| 13 | 13 | from django.core.urlresolvers import clear_url_caches |
| 14 | 14 | from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS, |
| 15 | 15 | reset_queries) |
| | 16 | from django.db.utils import IntegrityError |
| 16 | 17 | from django.http import QueryDict |
| 17 | 18 | from django.test import _doctest as doctest |
| 18 | 19 | from django.test.client import Client |
| … |
… |
|
| 298 | 299 | return |
| 299 | 300 | super(TransactionTestCase, self).__call__(result) |
| 300 | 301 | try: |
| 301 | | self._post_teardown() |
| | 302 | self._post_teardown(result) |
| 302 | 303 | except (KeyboardInterrupt, SystemExit): |
| 303 | 304 | raise |
| 304 | 305 | except Exception: |
| … |
… |
|
| 306 | 307 | result.addError(self, sys.exc_info()) |
| 307 | 308 | return |
| 308 | 309 | |
| 309 | | def _post_teardown(self): |
| | 310 | def _post_teardown(self, result): |
| 310 | 311 | """ Performs any post-test things. This includes: |
| 311 | 312 | |
| | 313 | * Tearing down database fixtures, if any. |
| 312 | 314 | * Putting back the original ROOT_URLCONF if it was changed. |
| 313 | 315 | * Force closing the connection, so that the next test gets |
| 314 | 316 | a clean cursor. |
| 315 | 317 | """ |
| 316 | | self._fixture_teardown() |
| | 318 | self._fixture_teardown(result) |
| 317 | 319 | self._urlconf_teardown() |
| 318 | 320 | # Some DB cursors include SQL statements as part of cursor |
| 319 | 321 | # creation. If you have a test that does rollback, the effect |
| … |
… |
|
| 325 | 327 | for connection in connections.all(): |
| 326 | 328 | connection.close() |
| 327 | 329 | |
| 328 | | def _fixture_teardown(self): |
| | 330 | def _fixture_teardown(self, result): |
| 329 | 331 | pass |
| 330 | 332 | |
| 331 | 333 | def _urlconf_teardown(self): |
| … |
… |
|
| 589 | 591 | 'database': db |
| 590 | 592 | }) |
| 591 | 593 | |
| 592 | | def _fixture_teardown(self): |
| | 594 | def _fixture_teardown(self, result): |
| 593 | 595 | if not connections_support_transactions(): |
| 594 | 596 | return super(TestCase, self)._fixture_teardown() |
| 595 | 597 | |
| … |
… |
|
| 602 | 604 | |
| 603 | 605 | restore_transaction_methods() |
| 604 | 606 | for db in databases: |
| 605 | | transaction.rollback(using=db) |
| 606 | | transaction.leave_transaction_management(using=db) |
| | 607 | # Force constraints check execution (on backends that support |
| | 608 | # deferring them) before rolling back the transaction. |
| | 609 | try: |
| | 610 | connections[db].check_constraints() |
| | 611 | except IntegrityError: |
| | 612 | result.addError(self, sys.exc_info()) |
| | 613 | finally: |
| | 614 | transaction.rollback(using=db) |
| | 615 | transaction.leave_transaction_management(using=db) |
| 607 | 616 | |
| 608 | 617 | def _deferredSkip(condition, reason): |
| 609 | 618 | def decorator(test_func): |
diff --git a/tests/regressiontests/multiple_database/tests.py b/tests/regressiontests/multiple_database/tests.py
|
a
|
b
|
|
| 1465 | 1465 | published=datetime.date(2008, 12, 16)) |
| 1466 | 1466 | |
| 1467 | 1467 | marty = Person.objects.using('other').create(pk=1, name="Marty Alchin") |
| 1468 | | pro.authors = [marty] |
| | 1468 | # Per the router in effect, writes go to the 'default' DB and so the |
| | 1469 | # manager will create m2m relationships on that DB. Derive a new manager |
| | 1470 | # associated with the 'other' DB so we don't create cross-DB FKs |
| | 1471 | author_m2m_manager_in_other_db = pro.authors.db_manager('other') |
| | 1472 | author_m2m_manager_in_other_db = [marty] |
| 1469 | 1473 | |
| 1470 | 1474 | self.assertEqual(pro.authors.db, 'other') |
| 1471 | 1475 | self.assertEqual(pro.authors.db_manager('default').db, 'default') |