Code

Ticket #16818: 16818.diff

File 16818.diff, 4.0 KB (added by kmtracey, 3 years ago)

Tentative fix

Line 
1diff -r 09437beebc4e django/db/models/query.py
2--- a/django/db/models/query.py Sun Nov 13 15:09:08 2011 +0000
3+++ b/django/db/models/query.py Sun Nov 13 11:17:03 2011 -0500
4@@ -394,18 +394,32 @@
5         self._for_write = True
6         connection = connections[self.db]
7         fields = self.model._meta.local_fields
8-        if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk
9-            and self.model._meta.has_auto_field):
10-            self.model._base_manager._insert(objs, fields=fields, using=self.db)
11+        if not transaction.is_managed(using=self.db):
12+            transaction.enter_transaction_management(using=self.db)
13+            forced_managed = True
14         else:
15-            objs_with_pk, objs_without_pk = partition(
16-                lambda o: o.pk is None,
17-                objs
18-            )
19-            if objs_with_pk:
20-                self.model._base_manager._insert(objs_with_pk, fields=fields, using=self.db)
21-            if objs_without_pk:
22-                self.model._base_manager._insert(objs_without_pk, fields=[f for f in fields if not isinstance(f, AutoField)], using=self.db)
23+            forced_managed = False
24+        try:
25+            if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk
26+                and self.model._meta.has_auto_field):
27+                self.model._base_manager._insert(objs, fields=fields, using=self.db)
28+            else:
29+                objs_with_pk, objs_without_pk = partition(
30+                    lambda o: o.pk is None,
31+                    objs
32+                )
33+                if objs_with_pk:
34+                    self.model._base_manager._insert(objs_with_pk, fields=fields, using=self.db)
35+                if objs_without_pk:
36+                    self.model._base_manager._insert(objs_without_pk, fields=[f for f in fields if not isinstance(f, AutoField)], using=self.db)
37+            if forced_managed:
38+                transaction.commit(using=self.db)
39+            else:
40+                transaction.commit_unless_managed(using=self.db)
41+        finally:
42+            if forced_managed:
43+                transaction.leave_transaction_management(using=self.db)
44+
45         return objs
46 
47     def get_or_create(self, **kwargs):
48diff -r 09437beebc4e tests/regressiontests/transactions_regress/models.py
49--- a/tests/regressiontests/transactions_regress/models.py      Sun Nov 13 15:09:08 2011 +0000
50+++ b/tests/regressiontests/transactions_regress/models.py      Sun Nov 13 11:17:03 2011 -0500
51@@ -2,3 +2,9 @@
52 
53 class Mod(models.Model):
54     fld = models.IntegerField()
55+
56+class M2mA(models.Model):
57+    others = models.ManyToManyField('M2mB')
58+
59+class M2mB(models.Model):
60+    fld = models.IntegerField()
61diff -r 09437beebc4e tests/regressiontests/transactions_regress/tests.py
62--- a/tests/regressiontests/transactions_regress/tests.py       Sun Nov 13 15:09:08 2011 +0000
63+++ b/tests/regressiontests/transactions_regress/tests.py       Sun Nov 13 11:17:03 2011 -0500
64@@ -5,7 +5,7 @@
65 from django.db.transaction import commit_on_success, commit_manually, TransactionManagementError
66 from django.test import TransactionTestCase, skipUnlessDBFeature
67 
68-from .models import Mod
69+from .models import Mod, M2mA, M2mB
70 
71 
72 class TestTransactionClosing(TransactionTestCase):
73@@ -164,3 +164,15 @@
74             _ = User.objects.all()[0]
75         except:
76             self.fail("A transaction consisting of a failed operation was not closed.")
77+
78+class TestManyToManyAddTransaction(TransactionTestCase):
79+    def test_manyrelated_add_commit(self):
80+        """test for 16818"""
81+        a = M2mA.objects.create()
82+        b = M2mB.objects.create(fld=10)
83+        a.others.add(b)
84+        # We're in a TransactionTestCase and have not changed transaction behavior from
85+        # default of "autocommit", so this rollback should not actually do anything. If it
86+        # does in fact un-do our add, that's a bug that the bulk insert was not auto-committed.
87+        transaction.rollback()
88+        self.assertQuerysetEqual(a.others.all(),['<M2mB: M2mB object>'])