Skip to content

Commit

Permalink
FIX: savepoint_rollback() after an IntegrityError gives TransactionMa…
Browse files Browse the repository at this point in the history
…nagementError #399

wrap save_m2m in transaction.atomic()

references #377
  • Loading branch information
bmihelac committed Mar 8, 2016
1 parent 79d4fc9 commit e7d081b
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
2 changes: 1 addition & 1 deletion import_export/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ def import_data(self, dataset, dry_run=False, raise_errors=False,
else:
with transaction.atomic():
self.save_instance(instance, real_dry_run)
self.save_m2m(instance, row, real_dry_run)
self.save_m2m(instance, row, real_dry_run)
# Add object info to RowResult for LogEntry
row_result.object_repr = force_text(instance)
row_result.object_id = instance.pk
Expand Down
20 changes: 20 additions & 0 deletions tests/core/migrations/0003_auto_20160308_0449.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-03-08 04:49
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0002_book_published_time'),
]

operations = [
migrations.AlterField(
model_name='category',
name='name',
field=models.CharField(max_length=100, unique=True),
),
]
5 changes: 4 additions & 1 deletion tests/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ def __str__(self):

@python_2_unicode_compatible
class Category(models.Model):
name = models.CharField(max_length=100)
name = models.CharField(
max_length=100,
unique=True,
)

def __str__(self):
return self.name
Expand Down
27 changes: 27 additions & 0 deletions tests/core/tests/resources_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ class Meta:
exclude = ('imported', )


class CategoryResource(resources.ModelResource):

class Meta:
model = Category


class ProfileResource(resources.ModelResource):
class Meta:
model = Profile
Expand Down Expand Up @@ -663,6 +669,27 @@ def test_m2m_import_with_transactions_error(self):
# Ensure the rollback has worked properly.
self.assertEqual(Profile.objects.count(), 0)

@skipUnlessDBFeature('supports_transactions')
def test_integrity_error_rollback_on_savem2m(self):
# savepoint_rollback() after an IntegrityError gives
# TransactionManagementError (#399)
class CategoryResourceRaisesIntegrityError(CategoryResource):
def save_m2m(self, instance, *args, **kwargs):
# force raising IntegrityError
Category.objects.create(name=instance.name)

resource = CategoryResourceRaisesIntegrityError()
headers = ['id', 'name']
rows = [
[None, 'foo'],
]
dataset = tablib.Dataset(*rows, headers=headers)
result = resource.import_data(
dataset,
use_transactions=True,
)
self.assertTrue(result.has_errors())


class ModelResourceFactoryTest(TestCase):

Expand Down

0 comments on commit e7d081b

Please sign in to comment.