Ticket #9964: 9964-r14913-bugfix.patch
File 9964-r14913-bugfix.patch, 11.0 KB (added by , 14 years ago) |
---|
-
django/db/backends/util.py
52 52 def __iter__(self): 53 53 return iter(self.cursor) 54 54 55 class CursorUseNotifyWrapper(object): 56 def __init__(self, cursor, on_use): 57 self.cursor = cursor 58 self.on_use = on_use 59 def __getattr__(self, attr): 60 self.on_use() 61 return getattr(self.cursor, attr) 62 def __iter__(self): 63 return iter(self.cursor) 64 55 65 ############################################### 56 66 # Converters from database (string) to Python # 57 67 ############################################### -
django/db/backends/__init__.py
22 22 self.settings_dict = settings_dict 23 23 self.alias = alias 24 24 self.use_debug_cursor = None 25 self.on_used = None 25 26 26 27 def __eq__(self, other): 27 28 return self.alias == other.alias … … 75 76 def cursor(self): 76 77 from django.conf import settings 77 78 cursor = self._cursor() 79 # Used by transaction mechanism to be notified that db was used 80 if self.on_used: 81 cursor = util.CursorUseNotifyWrapper(cursor, self.on_used) 78 82 if (self.use_debug_cursor or 79 83 (self.use_debug_cursor is None and settings.DEBUG)): 80 84 return self.make_debug_cursor(cursor) -
django/db/transaction.py
67 67 if thread_ident not in dirty or using not in dirty[thread_ident]: 68 68 dirty.setdefault(thread_ident, {}) 69 69 dirty[thread_ident][using] = False 70 def set_dirty_if_managed(): 71 if is_managed(using): set_dirty(using) 72 connection.on_used = set_dirty_if_managed 70 73 connection._enter_transaction_management(managed) 71 74 72 75 def leave_transaction_management(using=None): -
tests/regressiontests/transaction_regress/tests.py
1 from django.test import TransactionTestCase 2 from django.db import connection, transaction 3 from django.db.transaction import \ 4 commit_on_success, commit_manually, \ 5 TransactionManagementError 6 from models import Mod 7 8 class Test9964(TransactionTestCase): 9 10 def test_raw_committed_on_success(self): 11 12 @commit_on_success 13 def raw_sql(): 14 cursor = connection.cursor() 15 cursor.execute("INSERT into transaction_regress_mod (id,fld) values (17,18)") 16 17 raw_sql() 18 transaction.rollback() 19 try: 20 obj = Mod.objects.get(pk=17) 21 self.assertEqual(obj.fld, 18) 22 except Mod.DoesNotExist: 23 self.fail("transaction with raw sql not committed") 24 25 def test_commit_manually_enforced(self): 26 @commit_manually 27 def non_comitter(): 28 _ = Mod.objects.count() 29 30 self.assertRaises(TransactionManagementError, non_comitter) 31 32 def test_commit_manually_commit_ok(self): 33 @commit_manually 34 def committer(): 35 _ = Mod.objects.count() 36 transaction.commit() 37 38 try: 39 committer() 40 except TransactionManagementError: 41 self.fail("Commit did not clear the transaction state") 42 43 def test_commit_manually_rollback_ok(self): 44 @commit_manually 45 def roller_back(): 46 _ = Mod.objects.count() 47 transaction.rollback() 48 49 try: 50 roller_back() 51 except TransactionManagementError: 52 self.fail("Rollback did not clear the transaction state") 53 54 def test_commit_manually_enforced_after_commit(self): 55 @commit_manually 56 def fake_committer(): 57 _ = Mod.objects.count() 58 transaction.commit() 59 _ = Mod.objects.count() 60 61 self.assertRaises(TransactionManagementError, fake_committer) 62 63 def test_reuse_cursor_reference(self): 64 @commit_on_success 65 def reuse_cursor_ref(): 66 cursor = connection.cursor() 67 cursor.execute("INSERT into transaction_regress_mod (id,fld) values (1,2)") 68 transaction.rollback() 69 cursor.execute("INSERT into transaction_regress_mod (id,fld) values (1,2)") 70 71 reuse_cursor_ref() 72 transaction.rollback() 73 try: 74 obj = Mod.objects.get(pk=1) 75 self.assertEquals(obj.fld, 2) 76 except Mod.DoesNotExist: 77 self.fail("After ending a transaction, cursor use no longer sets dirty") 78 79 def test_6669(self): 80 81 from django.contrib.auth.models import User 82 83 @transaction.commit_on_success 84 def create_system_user(): 85 user = User.objects.create_user(username='system', password='iamr00t', email='root@SITENAME.com') 86 Mod.objects.create(fld=user.id) 87 88 try: 89 create_system_user() 90 except: 91 pass 92 93 try: 94 create_system_user() 95 except: 96 pass 97 98 User.objects.all()[0] -
tests/regressiontests/transaction_regress/models.py
1 from django.db import models 2 3 class Mod(models.Model): 4 fld = models.IntegerField() -
tests/regressiontests/delete_regress/tests.py
61 61 Book.objects.filter(pagecount__lt=250).delete() 62 62 transaction.commit() 63 63 self.assertEqual(1, Book.objects.count()) 64 transaction.commit() 64 65 65 66 class DeleteCascadeTests(TestCase): 66 67 def test_generic_relation_cascade(self): -
tests/regressiontests/fixtures_regress/tests.py
610 610 self.assertEqual(Thingy.objects.count(), 1) 611 611 transaction.rollback() 612 612 self.assertEqual(Thingy.objects.count(), 0) 613 transaction.commit() 613 614 614 615 def test_ticket_11101(self): 615 616 """Test that fixtures can be rolled back (ticket #11101).""" -
docs/topics/db/sql.txt
231 231 232 232 Transactions and raw SQL 233 233 ------------------------ 234 If you are using transaction decorators (such as ``commit_on_success``) to235 wrap your views and provide transaction control, you don't have to make a236 manual call to ``transaction.commit_unless_managed()`` -- you can manually237 commit if you want to, but you aren't required to, since the decorator will238 commit for you. However, if you don't manually commit your changes, you will239 need to manually mark the transaction as dirty, using240 ``transaction.set_dirty()``::241 234 242 @commit_on_success 243 def my_custom_sql_view(request, value): 244 from django.db import connection, transaction 245 cursor = connection.cursor() 235 .. versionchanged:: 1.3 246 236 247 # Data modifying operation 248 cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [value]) 237 If you write functions that modify the database via raw SQL, you need to 238 consider the transaction management mode they run under. If this may be 239 Django's default mode (by default or using the ``auto_commit`` 240 decorator), you need to make manual calls to 241 ``transaction.commit_unless_managed()`` to make sure the changes are 242 committed. If you are using transaction decorators (such as 243 ``commit_on_success``) to wrap your views and provide transaction 244 control, you don't have to make such calls. 249 245 250 # Since we modified data, mark the transaction as dirty251 transaction.set_dirty()252 246 253 # Data retrieval operation. This doesn't dirty the transaction,254 # so no call to set_dirty() is required.255 cursor.execute("SELECT foo FROM bar WHERE baz = %s", [value])256 row = cursor.fetchone()257 258 return render_to_response('template.html', {'row': row})259 260 The call to ``set_dirty()`` is made automatically when you use the Django ORM261 to make data modifying database calls. However, when you use raw SQL, Django262 has no way of knowing if your SQL modifies data or not. The manual call to263 ``set_dirty()`` ensures that Django knows that there are modifications that264 must be committed.265 266 247 Connections and cursors 267 248 ----------------------- 268 249 -
docs/releases/1.3.txt
330 330 331 331 332 332 333 Transaction management 334 ~~~~~~~~~~~~~~~~~~~~~~ 335 336 When using managed transactions -- that is, anything but the default 337 autocommit mode -- it is important when a transaction is marked as 338 "dirty". Dirty transactions are committed by the ``commit_on_success`` 339 decorator or the ``TransactionMiddleware``, and ``commit_manually`` 340 forces them to be closed explicitly; clean transactions "get a pass", 341 which means they are usually rolled back at the end of a request 342 when the connection is closed. 343 344 Until Django 1.3, transactions were only marked dirty when Django 345 was aware of a modifying operation performed in them; that is, either 346 some model was saved, some bulk update or delete was performed, or 347 the user explicitly called ``transaction.set_dirty()``. In Django 1.3, 348 a transaction is marked dirty when any database operation is performed; 349 this means you no longer need to set a transaction dirty explicitly 350 when you execute raw SQL or use a data-modifying ``select``. On the 351 other hand, you do need to explicitly close read-only transactions 352 under ``commit_manually``. For example, take a look at this code:: 353 354 @transaction.commit_manually 355 def my_view(request, name): 356 obj = get_object_or_404(MyObject, name__iexact=name) 357 return render_to_response('template', {'object':obj}) 358 359 Until Django 1.3, this works fine. With Django 1.3, this raises a 360 ``TransactionManagementError``; you need to end the transaction 361 explicitly, one way or another. 362 333 363 .. _deprecated-features-1.3: 334 364 335 365 Features deprecated in 1.3