Skip to content

Commit

Permalink
Merge pull request #919 from proofit404/transaction-rollback-flag
Browse files Browse the repository at this point in the history
Do not try to create revision if current transaction is under rollback.
  • Loading branch information
etianen committed Sep 24, 2022
2 parents d89b9f9 + 4a64e07 commit 284dd51
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 0 deletions.
7 changes: 7 additions & 0 deletions reversion/revisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,13 @@ def _create_revision_context(manage_manually, using, atomic):
_push_frame(manage_manually, using)
try:
yield
if transaction.get_connection(using).in_atomic_block and transaction.get_rollback(using):
# Transaction is in invalid state due to catched exception within yield statement.
# Do not try to create Revision, otherwise it would lead to the transaction management error.
#
# Atomic block could be called manually around `create_revision` context manager.
# That's why we have to check connection flag instead of `atomic` variable value.
return
# Only save for a db if that's the last stack frame for that db.
if not any(using in frame.db_versions for frame in _stack.get()[:-1]):
current_frame = _current_frame()
Expand Down
7 changes: 7 additions & 0 deletions tests/test_app/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,11 @@ class Migration(migrations.Migration):
('revision', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='reversion.revision')),
],
),
migrations.CreateModel(
name='TestModelWithUniqueConstraint',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=191, unique=True)),
],
),
]
8 changes: 8 additions & 0 deletions tests/test_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,11 @@ class TestModelInlineByNaturalKey(models.Model):
TestModelWithNaturalKey,
on_delete=models.CASCADE,
)


class TestModelWithUniqueConstraint(models.Model):

name = models.CharField(
max_length=191,
unique=True,
)
15 changes: 15 additions & 0 deletions tests/test_app/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
TestModel, TestModelRelated, TestModelParent, TestModelInline,
TestModelNestedInline,
TestModelInlineByNaturalKey, TestModelWithNaturalKey,
TestModelWithUniqueConstraint,
)
from test_app.tests.base import TestBase, TestModelMixin, TestModelParentMixin
import json
Expand Down Expand Up @@ -443,3 +444,17 @@ def testNaturalKeyInline(self):
'test_model_id': 1,
'id': 1,
})


class TransactionRollbackTest(TestBase):

def setUp(self):
reversion.register(TestModelWithUniqueConstraint)

def testTransactionInRollbackState(self):
with reversion.create_revision():
try:
TestModelWithUniqueConstraint.objects.create(name='A')
TestModelWithUniqueConstraint.objects.create(name='A')
except Exception:
pass

0 comments on commit 284dd51

Please sign in to comment.