Ticket #11665: better_constraint_checks_during_testing.v2.diff
File better_constraint_checks_during_testing.v2.diff, 38.6 KB (added by , 13 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. 3 from __future__ import with_statement 4 1 5 import sys 2 6 import os 3 7 import gzip … … class Command(BaseCommand): 166 170 (format, fixture_name, humanize(fixture_dir))) 167 171 try: 168 172 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 175 187 loaded_object_count += loaded_objects_in_fixture 176 188 fixture_object_count += objects_in_fixture 177 189 label_found = True -
django/db/__init__.py
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 -
django/db/backends/__init__.py
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 1c3bc7e..d0e997f 100644
a b try: 3 3 except ImportError: 4 4 import dummy_thread as thread 5 5 from threading import local 6 from contextlib import contextmanager 6 7 7 8 from django.conf import settings 8 9 from django.db import DEFAULT_DB_ALIAS … … class BaseDatabaseWrapper(local): 33 34 self.transaction_state = [] 34 35 self.savepoint_state = 0 35 36 self._dirty = None 37 38 self.constraint_checking_disabled = False 36 39 37 40 def __eq__(self, other): 38 41 return self.alias == other.alias … … class BaseDatabaseWrapper(local): 237 240 """ 238 241 if self.savepoint_state: 239 242 self._savepoint_commit(sid) 243 244 @contextmanager 245 def constraint_checks_disabled(self): 246 self.disable_constraint_checking() 247 try: 248 yield 249 finally: 250 if self.constraint_checking_disabled: 251 self.enable_constraint_checking() 252 253 254 def disable_constraint_checking(self): 255 """ 256 Backends can implement as needed to temporarily disable foreign key constraint 257 checking. 258 """ 259 self.constraint_checking_disabled = True 260 261 def enable_constraint_checking(self): 262 """ 263 Backends can implement as needed to re-enable foreign key constraint checking. 264 """ 265 self.constraint_checking_disabled = False 266 267 def check_constraints(self, table_names=None): 268 """ 269 Backends can override this method if they can apply constraint checking (e.g. via "SET CONSTRAINTS 270 ALL IMMEDIATE"). Should raise an IntegrityError if any invalid foreign key references are encountered. 271 """ 272 pass 240 273 241 274 def close(self): 242 275 if self.connection is not None: … … class BaseDatabaseIntrospection(object): 869 902 870 903 return sequence_list 871 904 905 def get_key_columns(self, cursor, table_name): 906 """ 907 Backends can override this to return a list of (column_name, referenced_table_name, 908 referenced_column_name) for all key columns in given table. 909 """ 910 raise NotImplementedError 911 912 def get_primary_key_column(self, cursor, table_name): 913 """ 914 Backends can override this to return the column name of the primary key for the given table. 915 """ 916 raise NotImplementedError 917 872 918 class BaseDatabaseClient(object): 873 919 """ 874 920 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): 34 34 get_table_description = complain 35 35 get_relations = complain 36 36 get_indexes = complain 37 get_key_columns = complain 37 38 38 39 class DatabaseWrapper(BaseDatabaseWrapper): 39 40 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..0d719b7 100644
a b class DatabaseWrapper(BaseDatabaseWrapper): 349 349 raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info()) 350 350 self.server_version = tuple([int(x) for x in m.groups()]) 351 351 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 self.constraint_checking_disabled = 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 self.constraint_checking_disabled = False 367 368 def check_constraints(self, table_names=None): 369 """ 370 Checks each table name in table-names for rows with invalid foreign key references. This method is 371 intended to be used in conjunction with `disable_constraint_checking()` and `enable_constraint_checking()`, to 372 determine if rows with invalid references were entered while constraint checks were off. 373 374 Raises an IntegrityError on the first invalid foreign key reference encountered (if any) and provides 375 detailed information about the invalid reference in the error message. 376 377 Backends can override this method if they can more directly apply constraint checking (e.g. via "SET CONSTRAINTS 378 ALL IMMEDIATE") 379 """ 380 cursor = self.cursor() 381 if table_names is None: 382 table_names = self.introspection.get_table_list(cursor) 383 for table_name in table_names: 384 primary_key_column_name = self.introspection.get_primary_key_column(cursor, table_name) 385 if not primary_key_column_name: 386 continue 387 key_columns = self.introspection.get_key_columns(cursor, table_name) 388 for column_name, referenced_table_name, referenced_column_name in key_columns: 389 cursor.execute(""" 390 SELECT REFERRING.`%s`, REFERRING.`%s` FROM `%s` as REFERRING 391 LEFT JOIN `%s` as REFERRED 392 ON (REFERRING.`%s` = REFERRED.`%s`) 393 WHERE REFERRING.`%s` IS NOT NULL 394 AND REFERRED.`%s` IS NULL""" 395 % (primary_key_column_name, column_name, table_name, referenced_table_name, 396 column_name, referenced_column_name, column_name, referenced_column_name)) 397 for bad_row in cursor.fetchall(): 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)) -
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): 51 51 representing all relationships to the given table. Indexes are 0-based. 52 52 """ 53 53 my_field_dict = self._name_to_index(cursor, table_name) 54 constraints = []54 constraints = self.get_key_columns(cursor, table_name) 55 55 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 = [] 56 68 try: 57 # This should work for MySQL 5.0.58 69 cursor.execute(""" 59 70 SELECT column_name, referenced_table_name, referenced_column_name 60 71 FROM information_schema.key_column_usage … … class DatabaseIntrospection(BaseDatabaseIntrospection): 62 73 AND table_schema = DATABASE() 63 74 AND referenced_table_name IS NOT NULL 64 75 AND referenced_column_name IS NOT NULL""", [table_name]) 65 constraints.extend(cursor.fetchall())76 key_columns.extend(cursor.fetchall()) 66 77 except (ProgrammingError, OperationalError): 67 78 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 68 79 # Go through all constraints and save the equal matches. … … class DatabaseIntrospection(BaseDatabaseIntrospection): 74 85 if match == None: 75 86 break 76 87 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 85 99 86 100 def get_indexes(self, cursor, table_name): 87 101 """ -
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): 428 428 self.introspection = DatabaseIntrospection(self) 429 429 self.validation = BaseDatabaseValidation(self) 430 430 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 431 439 def _valid_connection(self): 432 440 return self.connection is not None 433 441 -
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): 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 _get_pg_version(self): 110 118 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): 206 206 connection_created.send(sender=self.__class__, connection=self) 207 207 return self.connection.cursor(factory=SQLiteCursorWrapper) 208 208 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 \ 240 foreign 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 209 244 def close(self): 210 245 # If database is in memory, closing the connection destroys the 211 246 # 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): 103 103 104 104 return relations 105 105 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 106 135 def get_indexes(self, cursor, table_name): 107 136 """ 108 137 Returns a dictionary of fieldname -> infodict for the given table, … … class DatabaseIntrospection(BaseDatabaseIntrospection): 127 156 name = info[0][2] # seqno, cid, name 128 157 indexes[name]['unique'] = True 129 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 130 174 131 175 def _table_info(self, cursor, name): 132 176 cursor.execute('PRAGMA table_info(%s)' % self.connection.ops.quote_name(name)) -
django/db/backends/util.py
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 -
django/test/__init__.py
diff --git a/django/test/__init__.py b/django/test/__init__.py index 68aea9a..04d985d 100644
a b Django Unit Test and Doctest framework. 3 3 """ 4 4 5 5 from django.test.client import Client, RequestFactory 6 from django.test.testcases import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature 6 from django.test.testcases import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature, ignore_num_queries 7 7 from django.test.utils import Approximate -
django/test/testcases.py
diff --git a/django/test/testcases.py b/django/test/testcases.py index e767712..98c6887 100644
a b from django.utils.encoding import smart_str 23 23 __all__ = ('DocTestRunner', 'OutputChecker', 'TestCase', 'TransactionTestCase', 24 24 'skipIfDBFeature', 'skipUnlessDBFeature') 25 25 26 27 def ignore_num_queries(fn): 28 @wraps(fn) 29 def num_queries_ignored(*args, **kwargs): 30 connections._ignore_num_queries = True 31 try: 32 return fn(*args, **kwargs) 33 finally: 34 connections._ignore_num_queries = False 35 return num_queries_ignored 36 26 37 normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s) 27 38 normalize_decimals = lambda s: re.sub(r"Decimal\('(\d+(\.\d*)?)'\)", lambda m: "Decimal(\"%s\")" % m.groups()[0], s) 28 39 … … def to_list(value): 39 50 40 51 real_commit = transaction.commit 41 52 real_rollback = transaction.rollback 53 real_commit_unless_managed = transaction.commit_unless_managed 54 real_rollback_unless_managed = transaction.rollback_unless_managed 42 55 real_enter_transaction_management = transaction.enter_transaction_management 43 56 real_leave_transaction_management = transaction.leave_transaction_management 44 57 real_managed = transaction.managed … … real_managed = transaction.managed 46 59 def nop(*args, **kwargs): 47 60 return 48 61 62 @ignore_num_queries 63 def check_constraints(using=None): 64 """ 65 Emulate the constraint check behavior that normally occurs when a transaction is rolled back or committed. 66 """ 67 if using is None: 68 using = DEFAULT_DB_ALIAS 69 connection = connections[using] 70 # Don't check constraints if they have been manually disabled 71 if not connection.constraint_checking_disabled: 72 connection.check_constraints() 73 49 74 def disable_transaction_methods(): 50 transaction.commit = nop75 transaction.commit = check_constraints 51 76 transaction.rollback = nop 77 transaction.commit_unless_managed = check_constraints 78 transaction.rollback_unless_managed = nop 52 79 transaction.enter_transaction_management = nop 53 80 transaction.leave_transaction_management = nop 54 81 transaction.managed = nop … … def disable_transaction_methods(): 56 83 def restore_transaction_methods(): 57 84 transaction.commit = real_commit 58 85 transaction.rollback = real_rollback 86 transaction.commit_unless_managed = real_commit_unless_managed 87 transaction.rollback_unless_managed = real_rollback_unless_managed 59 88 transaction.enter_transaction_management = real_enter_transaction_management 60 89 transaction.leave_transaction_management = real_leave_transaction_management 61 90 transaction.managed = real_managed … … class TestCase(TransactionTestCase): 580 609 581 610 from django.contrib.sites.models import Site 582 611 Site.objects.clear_cache() 612 613 from django.contrib.contenttypes.models import ContentType 614 ContentType.objects.clear_cache() 583 615 584 616 for db in databases: 585 617 if hasattr(self, 'fixtures'): -
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. 142 142 The InnoDB_ engine is fully transactional and supports foreign key references 143 143 and is probably the best choice at this point in time. 144 144 145 .. versionchanged:: 1.4 146 147 In previous versions of Django, fixtures with forward references (i.e. 148 relations to rows that have not yet been inserted into the database) would fail 149 to load when using the InnoDB storage engine. This was due to the fact that InnoDB 150 deviates from the SQL standard by checking foreign key constraints immediately 151 instead of deferring the check until the transaction is committed. This 152 problem has been resolved in Django 1.4. Fixture data is now loaded with foreign key 153 checks turned off; foreign key checks are then re-enabled when the data has 154 finished loading, at which point the entire table is checked for invalid foreign 155 key references and an `IntegrityError` is raised if any are found. 156 145 157 .. _storage engines: http://dev.mysql.com/doc/refman/5.5/en/storage-engines.html 146 158 .. _MyISAM: http://dev.mysql.com/doc/refman/5.5/en/myisam-storage-engine.html 147 159 .. _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. 3 from __future__ import with_statement 4 1 5 # -*- coding: utf-8 -*- 2 6 from datetime import datetime 3 7 from StringIO import StringIO … … from xml.dom import minidom 5 9 6 10 from django.conf import settings 7 11 from django.core import serializers 8 from django.db import transaction 12 from django.db import transaction, connection 9 13 from django.test import TestCase, TransactionTestCase, Approximate 10 14 from django.utils import simplejson, unittest 11 15 … … class SerializersTransactionTestBase(object): 252 256 transaction.enter_transaction_management() 253 257 transaction.managed(True) 254 258 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() 257 262 transaction.commit() 258 263 transaction.leave_transaction_management() 259 264 -
tests/regressiontests/backends/tests.py
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index 29db6a7..be5d6f4 100644
a b 1 1 # -*- coding: utf-8 -*- 2 2 # Unit and doctests for specific database backends. 3 from __future__ import with_statement 3 4 import datetime 4 5 5 6 from django.conf import settings 6 7 from django.core.management.color import no_style 7 from django.db import backend, connection, connections, DEFAULT_DB_ALIAS, IntegrityError 8 from django.db import backend, connection, connections, DEFAULT_DB_ALIAS, IntegrityError, transaction 8 9 from django.db.backends.signals import connection_created 9 10 from django.db.backends.postgresql_psycopg2 import version as pg_version 10 11 from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase … … class FkConstraintsTests(TransactionTestCase): 328 329 try: 329 330 a.save() 330 331 except IntegrityError: 331 pass 332 return 333 self.skipTest("This backend does not support integrity checks.") 332 334 333 335 def test_integrity_checks_on_update(self): 334 336 """ … … class FkConstraintsTests(TransactionTestCase): 343 345 try: 344 346 a.save() 345 347 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. Also, 354 should set disabled flag. 355 """ 356 with transaction.commit_manually(): 357 # Create an Article. 358 models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) 359 # Retrive it from the DB 360 a = models.Article.objects.get(headline="Test article") 361 a.reporter_id = 30 362 try: 363 connection.disable_constraint_checking() 364 self.assertTrue(connection.constraint_checking_disabled) 365 a.save() 366 connection.enable_constraint_checking() 367 except IntegrityError: 368 self.fail("IntegrityError should not have occurred.") 369 finally: 370 transaction.rollback() 371 372 def test_disable_constraint_checks_context_manager(self): 373 """ 374 When constraint checks are disabled (using context manager), should be able to write bad data without IntegrityErrors. 375 """ 376 with transaction.commit_manually(): 377 # Create an Article. 378 models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) 379 # Retrive it from the DB 380 a = models.Article.objects.get(headline="Test article") 381 a.reporter_id = 30 382 try: 383 with connection.constraint_checks_disabled(): 384 self.assertTrue(connection.constraint_checking_disabled) 385 a.save() 386 except IntegrityError: 387 self.fail("IntegrityError should not have occurred.") 388 finally: 389 transaction.rollback() 390 391 def test_check_constraints(self): 392 """ 393 Constraint checks should raise an IntegrityError when bad data is in the DB. 394 """ 395 with transaction.commit_manually(): 396 # Create an Article. 397 models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) 398 # Retrive it from the DB 399 a = models.Article.objects.get(headline="Test article") 400 a.reporter_id = 30 401 try: 402 with connection.constraint_checks_disabled(): 403 a.save() 404 with self.assertRaises(IntegrityError): 405 connection.check_constraints() 406 finally: 407 transaction.rollback() -
tests/regressiontests/comment_tests/tests/templatetag_tests.py
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() -
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): 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 366 395 class 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): 95 95 # That's {field_index: (field_index_other_table, other_table)} 96 96 self.assertEqual(relations, {3: (0, Reporter._meta.db_table)}) 97 97 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 98 108 def test_get_indexes(self): 99 109 cursor = connection.cursor() 100 110 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 6 6 the serializers. This includes all valid data values, plus 7 7 forward, backwards and self references. 8 8 """ 9 # This is necessary in Python 2.5 to enable the with statement, in 2.6 10 # and up it is no longer necessary. 9 11 from __future__ import with_statement 10 12 11 13 import datetime … … def serializerTest(format, self): 382 384 objects = [] 383 385 instance_count = {} 384 386 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)) 386 389 387 390 # Get a count of the number of objects created for each class 388 391 for klass in instance_count: -
tests/regressiontests/test_utils/models.py
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',) -
tests/regressiontests/test_utils/tests.py
diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py index a35b0bc..6e26b24 100644
a b 1 1 from __future__ import with_statement 2 2 3 from django.test import TestCase, skipUnlessDBFeature 3 from django.test import TestCase, skipUnlessDBFeature, ignore_num_queries 4 4 from django.utils.unittest import skip 5 from django.db import IntegrityError 5 6 6 from models import Person 7 from models import Person, Pet 7 8 8 9 9 10 class SkippingTestCase(TestCase): … … class AssertNumQueriesTests(TestCase): 47 48 self.client.get("/test_utils/get_person/%s/" % person.pk) 48 49 self.client.get("/test_utils/get_person/%s/" % person.pk) 49 50 self.assertNumQueries(2, test_func) 51 52 def test_assert_num_queries_ignore_decorator(self): 53 person = Person.objects.create(name='test') 54 55 @ignore_num_queries 56 def test_func(): 57 self.client.get("/test_utils/get_person/%s/" % person.pk) 58 self.client.get("/test_utils/get_person/%s/" % person.pk) 59 self.assertNumQueries(0, test_func) 50 60 51 61 class AssertNumQueriesContextManagerTests(TestCase): 52 62 urls = 'regressiontests.test_utils.urls' … … class AssertNumQueriesContextManagerTests(TestCase): 86 96 self.client.get("/test_utils/get_person/%s/" % person.pk) 87 97 88 98 99 class TransactionPatchingTests(TestCase): 100 def test_bad_data_should_raise_data_integrity_error(self): 101 """ 102 Ensure bad data cannot be saved to DB during tests. 103 """ 104 bill = Person.objects.create(name="Bill") 105 dog = Pet.objects.create(name="Spot", owner=bill) 106 dog.owner_id = 20 # Does not exist 107 with self.assertRaises(IntegrityError): 108 dog.save() 109 89 110 class SaveRestoreWarningState(TestCase): 90 111 def test_save_restore_warnings_state(self): 91 112 """