Fixed #24318 -- Set the transaction isolation level with psycopg >= 2.4.2.
This commit is contained in:
parent
1379165b35
commit
76356d963c
|
@ -127,10 +127,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(DatabaseWrapper, self).__init__(*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.features = DatabaseFeatures(self)
|
||||||
self.ops = DatabaseOperations(self)
|
self.ops = DatabaseOperations(self)
|
||||||
self.client = DatabaseClient(self)
|
self.client = DatabaseClient(self)
|
||||||
|
@ -165,7 +161,29 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
return conn_params
|
return conn_params
|
||||||
|
|
||||||
def get_new_connection(self, 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):
|
def init_connection_state(self):
|
||||||
settings_dict = self.settings_dict
|
settings_dict = self.settings_dict
|
||||||
|
|
|
@ -19,3 +19,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed crash in ``contrib.sites`` migrations when a default database isn't
|
* Fixed crash in ``contrib.sites`` migrations when a default database isn't
|
||||||
used (:ticket:`24332`).
|
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:
|
finally:
|
||||||
new_connection.close()
|
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):
|
def _select(self, val):
|
||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
cursor.execute("SELECT %s", (val,))
|
cursor.execute("SELECT %s", (val,))
|
||||||
|
|
Loading…
Reference in New Issue