mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #24318 -- Set the transaction isolation level with psycopg >= 2.4.2.
This commit is contained in:
		| @@ -127,10 +127,6 @@ class DatabaseWrapper(BaseDatabaseWrapper): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super(DatabaseWrapper, self).__init__(*args, **kwargs) | ||||
|  | ||||
|         opts = self.settings_dict["OPTIONS"] | ||||
|         RC = psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED | ||||
|         self.isolation_level = opts.get('isolation_level', RC) | ||||
|  | ||||
|         self.features = DatabaseFeatures(self) | ||||
|         self.ops = DatabaseOperations(self) | ||||
|         self.client = DatabaseClient(self) | ||||
| @@ -165,7 +161,29 @@ class DatabaseWrapper(BaseDatabaseWrapper): | ||||
|         return conn_params | ||||
|  | ||||
|     def get_new_connection(self, conn_params): | ||||
|         return Database.connect(**conn_params) | ||||
|         connection = Database.connect(**conn_params) | ||||
|  | ||||
|         # self.isolation_level must be set: | ||||
|         # - after connecting to the database in order to obtain the database's | ||||
|         #   default when no value is explicitly specified in options. | ||||
|         # - before calling _set_autocommit() because if autocommit is on, that | ||||
|         #   will set connection.isolation_level to ISOLATION_LEVEL_AUTOCOMMIT; | ||||
|         #   and if autocommit is off, on psycopg2 < 2.4.2, _set_autocommit() | ||||
|         #   needs self.isolation_level. | ||||
|         options = self.settings_dict['OPTIONS'] | ||||
|         try: | ||||
|             self.isolation_level = options['isolation_level'] | ||||
|         except KeyError: | ||||
|             self.isolation_level = connection.isolation_level | ||||
|         else: | ||||
|             # Set the isolation level to the value from OPTIONS. This isn't | ||||
|             # needed on psycopg2 < 2.4.2 because it happens as a side-effect | ||||
|             # of _set_autocommit(False). | ||||
|             if (self.isolation_level != connection.isolation_level and | ||||
|                     self.psycopg2_version >= (2, 4, 2)): | ||||
|                 connection.set_session(isolation_level=self.isolation_level) | ||||
|  | ||||
|         return connection | ||||
|  | ||||
|     def init_connection_state(self): | ||||
|         settings_dict = self.settings_dict | ||||
|   | ||||
| @@ -19,3 +19,7 @@ Bugfixes | ||||
|  | ||||
| * Fixed crash in ``contrib.sites`` migrations when a default database isn't | ||||
|   used (:ticket:`24332`). | ||||
|  | ||||
| * Added the ability to set the isolation level on PostgreSQL with psycopg2 ≥ | ||||
|   2.4.2 (:ticket:`24318`). It was advertised as a new feature in Django 1.6 | ||||
|   but it didn't work in practice. | ||||
|   | ||||
| @@ -237,6 +237,34 @@ class PostgreSQLTests(TestCase): | ||||
|         finally: | ||||
|             new_connection.close() | ||||
|  | ||||
|     def test_connect_isolation_level(self): | ||||
|         """ | ||||
|         Regression test for #18130 and #24318. | ||||
|         """ | ||||
|         from psycopg2.extensions import ( | ||||
|             ISOLATION_LEVEL_READ_COMMITTED as read_committed, | ||||
|             ISOLATION_LEVEL_SERIALIZABLE as serializable, | ||||
|         ) | ||||
|  | ||||
|         # Since this is a django.test.TestCase, a transaction is in progress | ||||
|         # and the isolation level isn't reported as 0. This test assumes that | ||||
|         # PostgreSQL is configured with the default isolation level. | ||||
|  | ||||
|         # Check the level on the psycopg2 connection, not the Django wrapper. | ||||
|         self.assertEqual(connection.connection.isolation_level, read_committed) | ||||
|  | ||||
|         databases = copy.deepcopy(settings.DATABASES) | ||||
|         databases[DEFAULT_DB_ALIAS]['OPTIONS']['isolation_level'] = serializable | ||||
|         new_connections = ConnectionHandler(databases) | ||||
|         new_connection = new_connections[DEFAULT_DB_ALIAS] | ||||
|         try: | ||||
|             # Start a transaction so the isolation level isn't reported as 0. | ||||
|             new_connection.set_autocommit(False) | ||||
|             # Check the level on the psycopg2 connection, not the Django wrapper. | ||||
|             self.assertEqual(new_connection.connection.isolation_level, serializable) | ||||
|         finally: | ||||
|             new_connection.close() | ||||
|  | ||||
|     def _select(self, val): | ||||
|         with connection.cursor() as cursor: | ||||
|             cursor.execute("SELECT %s", (val,)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user