diff -r 09437beebc4e django/db/models/query.py
a
|
b
|
|
394 | 394 | self._for_write = True |
395 | 395 | connection = connections[self.db] |
396 | 396 | fields = self.model._meta.local_fields |
397 | | if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk |
398 | | and self.model._meta.has_auto_field): |
399 | | self.model._base_manager._insert(objs, fields=fields, using=self.db) |
| 397 | if not transaction.is_managed(using=self.db): |
| 398 | transaction.enter_transaction_management(using=self.db) |
| 399 | forced_managed = True |
400 | 400 | else: |
401 | | objs_with_pk, objs_without_pk = partition( |
402 | | lambda o: o.pk is None, |
403 | | objs |
404 | | ) |
405 | | if objs_with_pk: |
406 | | self.model._base_manager._insert(objs_with_pk, fields=fields, using=self.db) |
407 | | if objs_without_pk: |
408 | | self.model._base_manager._insert(objs_without_pk, fields=[f for f in fields if not isinstance(f, AutoField)], using=self.db) |
| 401 | forced_managed = False |
| 402 | try: |
| 403 | if (connection.features.can_combine_inserts_with_and_without_auto_increment_pk |
| 404 | and self.model._meta.has_auto_field): |
| 405 | self.model._base_manager._insert(objs, fields=fields, using=self.db) |
| 406 | else: |
| 407 | objs_with_pk, objs_without_pk = partition( |
| 408 | lambda o: o.pk is None, |
| 409 | objs |
| 410 | ) |
| 411 | if objs_with_pk: |
| 412 | self.model._base_manager._insert(objs_with_pk, fields=fields, using=self.db) |
| 413 | if objs_without_pk: |
| 414 | self.model._base_manager._insert(objs_without_pk, fields=[f for f in fields if not isinstance(f, AutoField)], using=self.db) |
| 415 | if forced_managed: |
| 416 | transaction.commit(using=self.db) |
| 417 | else: |
| 418 | transaction.commit_unless_managed(using=self.db) |
| 419 | finally: |
| 420 | if forced_managed: |
| 421 | transaction.leave_transaction_management(using=self.db) |
| 422 | |
409 | 423 | return objs |
410 | 424 | |
411 | 425 | def get_or_create(self, **kwargs): |
diff -r 09437beebc4e tests/regressiontests/transactions_regress/models.py
a
|
b
|
|
2 | 2 | |
3 | 3 | class Mod(models.Model): |
4 | 4 | fld = models.IntegerField() |
| 5 | |
| 6 | class M2mA(models.Model): |
| 7 | others = models.ManyToManyField('M2mB') |
| 8 | |
| 9 | class M2mB(models.Model): |
| 10 | fld = models.IntegerField() |
diff -r 09437beebc4e tests/regressiontests/transactions_regress/tests.py
a
|
b
|
|
5 | 5 | from django.db.transaction import commit_on_success, commit_manually, TransactionManagementError |
6 | 6 | from django.test import TransactionTestCase, skipUnlessDBFeature |
7 | 7 | |
8 | | from .models import Mod |
| 8 | from .models import Mod, M2mA, M2mB |
9 | 9 | |
10 | 10 | |
11 | 11 | class TestTransactionClosing(TransactionTestCase): |
… |
… |
|
164 | 164 | _ = User.objects.all()[0] |
165 | 165 | except: |
166 | 166 | self.fail("A transaction consisting of a failed operation was not closed.") |
| 167 | |
| 168 | class TestManyToManyAddTransaction(TransactionTestCase): |
| 169 | def test_manyrelated_add_commit(self): |
| 170 | """test for 16818""" |
| 171 | a = M2mA.objects.create() |
| 172 | b = M2mB.objects.create(fld=10) |
| 173 | a.others.add(b) |
| 174 | # We're in a TransactionTestCase and have not changed transaction behavior from |
| 175 | # default of "autocommit", so this rollback should not actually do anything. If it |
| 176 | # does in fact un-do our add, that's a bug that the bulk insert was not auto-committed. |
| 177 | transaction.rollback() |
| 178 | self.assertQuerysetEqual(a.others.all(),['<M2mB: M2mB object>']) |