Loading django/db/backends/postgresql_psycopg2/base.py +7 −2 Original line number Diff line number Diff line Loading @@ -83,7 +83,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): if autocommit: level = psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT else: level = psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED level = self.settings_dict["OPTIONS"].get('isolation_level', psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) self._set_isolation_level(level) self.ops = DatabaseOperations(self) self.client = DatabaseClient(self) Loading @@ -104,6 +105,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): conn_params.update(settings_dict['OPTIONS']) if 'autocommit' in conn_params: del conn_params['autocommit'] if 'isolation_level' in conn_params: del conn_params['isolation_level'] if settings_dict['USER']: conn_params['user'] = settings_dict['USER'] if settings_dict['PASSWORD']: Loading Loading @@ -170,7 +173,9 @@ class DatabaseWrapper(BaseDatabaseWrapper): the same transaction is visible across all the queries. """ if self.features.uses_autocommit and managed and not self.isolation_level: self._set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) level = self.settings_dict["OPTIONS"].get('isolation_level', psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) self._set_isolation_level(level) def _leave_transaction_management(self, managed): """ Loading docs/ref/databases.txt +33 −2 Original line number Diff line number Diff line Loading @@ -143,8 +143,11 @@ autocommit behavior is enabled by setting the ``autocommit`` key in the :setting:`OPTIONS` part of your database configuration in :setting:`DATABASES`:: DATABASES = { # ... 'OPTIONS': { 'autocommit': True, }, } In this configuration, Django still ensures that :ref:`delete() Loading @@ -168,6 +171,34 @@ You should also audit your existing code for any instances of this behavior before enabling this feature. It's faster, but it provides less automatic protection for multi-call operations. Isolation level ~~~~~~~~~~~~~~~ .. versionadded:: 1.6 Like PostgreSQL itself, Django defaults to the ``READ COMMITTED`` `isolation level <postgresql-isolation-levels>`_. If you need a higher isolation level such as ``REPEATABLE READ`` or ``SERIALIZABLE``, set it in the :setting:`OPTIONS` part of your database configuration in :setting:`DATABASES`:: import psycopg2.extensions DATABASES = { # ... 'OPTIONS': { 'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE, }, } .. note:: Under higher isolation levels, your application should be prepared to handle exceptions raised on serialization failures. This option is designed for advanced uses. .. _postgresql-isolation-levels: http://www.postgresql.org/docs/devel/static/transaction-iso.html Indexes for ``varchar`` and ``text`` columns ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading docs/releases/1.6.txt +2 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,8 @@ Minor features * The admin list columns have a ``column-<field_name>`` class in the HTML so the columns header can be styled with CSS, e.g. to set a column width. * The isolation level can be customized under PostgreSQL. Backwards incompatible changes in 1.6 ===================================== Loading tests/transactions_regress/tests.py +13 −11 Original line number Diff line number Diff line Loading @@ -242,17 +242,18 @@ class TestNewConnection(TransactionTestCase): @skipUnless(connection.vendor == 'postgresql', "This test only valid for PostgreSQL") class TestPostgresAutocommit(TransactionTestCase): class TestPostgresAutocommitAndIsolation(TransactionTestCase): """ Tests to make sure psycopg2's autocommit mode is restored after entering and leaving transaction management. Refs #16047. Tests to make sure psycopg2's autocommit mode and isolation level is restored after entering and leaving transaction management. Refs #16047, #18130. """ def setUp(self): from psycopg2.extensions import (ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE, TRANSACTION_STATUS_IDLE) self._autocommit = ISOLATION_LEVEL_AUTOCOMMIT self._read_committed = ISOLATION_LEVEL_READ_COMMITTED self._serializable = ISOLATION_LEVEL_SERIALIZABLE self._idle = TRANSACTION_STATUS_IDLE # We want a clean backend with autocommit = True, so Loading @@ -261,6 +262,7 @@ class TestPostgresAutocommit(TransactionTestCase): settings = self._old_backend.settings_dict.copy() opts = settings['OPTIONS'].copy() opts['autocommit'] = True opts['isolation_level'] = ISOLATION_LEVEL_SERIALIZABLE settings['OPTIONS'] = opts new_backend = self._old_backend.__class__(settings, DEFAULT_DB_ALIAS) connections[DEFAULT_DB_ALIAS] = new_backend Loading @@ -279,7 +281,7 @@ class TestPostgresAutocommit(TransactionTestCase): def test_transaction_management(self): transaction.enter_transaction_management() transaction.managed(True) self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._autocommit) Loading @@ -287,13 +289,13 @@ class TestPostgresAutocommit(TransactionTestCase): def test_transaction_stacking(self): transaction.enter_transaction_management() transaction.managed(True) self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.enter_transaction_management() self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._autocommit) Loading @@ -301,7 +303,7 @@ class TestPostgresAutocommit(TransactionTestCase): def test_enter_autocommit(self): transaction.enter_transaction_management() transaction.managed(True) self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) list(Mod.objects.all()) self.assertTrue(transaction.is_dirty()) # Enter autocommit mode again. Loading @@ -314,7 +316,7 @@ class TestPostgresAutocommit(TransactionTestCase): list(Mod.objects.all()) self.assertFalse(transaction.is_dirty()) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._autocommit) Loading Loading
django/db/backends/postgresql_psycopg2/base.py +7 −2 Original line number Diff line number Diff line Loading @@ -83,7 +83,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): if autocommit: level = psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT else: level = psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED level = self.settings_dict["OPTIONS"].get('isolation_level', psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) self._set_isolation_level(level) self.ops = DatabaseOperations(self) self.client = DatabaseClient(self) Loading @@ -104,6 +105,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): conn_params.update(settings_dict['OPTIONS']) if 'autocommit' in conn_params: del conn_params['autocommit'] if 'isolation_level' in conn_params: del conn_params['isolation_level'] if settings_dict['USER']: conn_params['user'] = settings_dict['USER'] if settings_dict['PASSWORD']: Loading Loading @@ -170,7 +173,9 @@ class DatabaseWrapper(BaseDatabaseWrapper): the same transaction is visible across all the queries. """ if self.features.uses_autocommit and managed and not self.isolation_level: self._set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) level = self.settings_dict["OPTIONS"].get('isolation_level', psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED) self._set_isolation_level(level) def _leave_transaction_management(self, managed): """ Loading
docs/ref/databases.txt +33 −2 Original line number Diff line number Diff line Loading @@ -143,8 +143,11 @@ autocommit behavior is enabled by setting the ``autocommit`` key in the :setting:`OPTIONS` part of your database configuration in :setting:`DATABASES`:: DATABASES = { # ... 'OPTIONS': { 'autocommit': True, }, } In this configuration, Django still ensures that :ref:`delete() Loading @@ -168,6 +171,34 @@ You should also audit your existing code for any instances of this behavior before enabling this feature. It's faster, but it provides less automatic protection for multi-call operations. Isolation level ~~~~~~~~~~~~~~~ .. versionadded:: 1.6 Like PostgreSQL itself, Django defaults to the ``READ COMMITTED`` `isolation level <postgresql-isolation-levels>`_. If you need a higher isolation level such as ``REPEATABLE READ`` or ``SERIALIZABLE``, set it in the :setting:`OPTIONS` part of your database configuration in :setting:`DATABASES`:: import psycopg2.extensions DATABASES = { # ... 'OPTIONS': { 'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE, }, } .. note:: Under higher isolation levels, your application should be prepared to handle exceptions raised on serialization failures. This option is designed for advanced uses. .. _postgresql-isolation-levels: http://www.postgresql.org/docs/devel/static/transaction-iso.html Indexes for ``varchar`` and ``text`` columns ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading
docs/releases/1.6.txt +2 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,8 @@ Minor features * The admin list columns have a ``column-<field_name>`` class in the HTML so the columns header can be styled with CSS, e.g. to set a column width. * The isolation level can be customized under PostgreSQL. Backwards incompatible changes in 1.6 ===================================== Loading
tests/transactions_regress/tests.py +13 −11 Original line number Diff line number Diff line Loading @@ -242,17 +242,18 @@ class TestNewConnection(TransactionTestCase): @skipUnless(connection.vendor == 'postgresql', "This test only valid for PostgreSQL") class TestPostgresAutocommit(TransactionTestCase): class TestPostgresAutocommitAndIsolation(TransactionTestCase): """ Tests to make sure psycopg2's autocommit mode is restored after entering and leaving transaction management. Refs #16047. Tests to make sure psycopg2's autocommit mode and isolation level is restored after entering and leaving transaction management. Refs #16047, #18130. """ def setUp(self): from psycopg2.extensions import (ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE, TRANSACTION_STATUS_IDLE) self._autocommit = ISOLATION_LEVEL_AUTOCOMMIT self._read_committed = ISOLATION_LEVEL_READ_COMMITTED self._serializable = ISOLATION_LEVEL_SERIALIZABLE self._idle = TRANSACTION_STATUS_IDLE # We want a clean backend with autocommit = True, so Loading @@ -261,6 +262,7 @@ class TestPostgresAutocommit(TransactionTestCase): settings = self._old_backend.settings_dict.copy() opts = settings['OPTIONS'].copy() opts['autocommit'] = True opts['isolation_level'] = ISOLATION_LEVEL_SERIALIZABLE settings['OPTIONS'] = opts new_backend = self._old_backend.__class__(settings, DEFAULT_DB_ALIAS) connections[DEFAULT_DB_ALIAS] = new_backend Loading @@ -279,7 +281,7 @@ class TestPostgresAutocommit(TransactionTestCase): def test_transaction_management(self): transaction.enter_transaction_management() transaction.managed(True) self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._autocommit) Loading @@ -287,13 +289,13 @@ class TestPostgresAutocommit(TransactionTestCase): def test_transaction_stacking(self): transaction.enter_transaction_management() transaction.managed(True) self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.enter_transaction_management() self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._autocommit) Loading @@ -301,7 +303,7 @@ class TestPostgresAutocommit(TransactionTestCase): def test_enter_autocommit(self): transaction.enter_transaction_management() transaction.managed(True) self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) list(Mod.objects.all()) self.assertTrue(transaction.is_dirty()) # Enter autocommit mode again. Loading @@ -314,7 +316,7 @@ class TestPostgresAutocommit(TransactionTestCase): list(Mod.objects.all()) self.assertFalse(transaction.is_dirty()) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._read_committed) self.assertEqual(connection.isolation_level, self._serializable) transaction.leave_transaction_management() self.assertEqual(connection.isolation_level, self._autocommit) Loading