Skip to content

Commit 18cf517

Browse files
committed
Merge pull request saxix#60 from ticosax/conditional-concurrency-no-meta
ConditionalConcurrencyField can be used without having ConcurrencyMeta defiend.
2 parents 429fbd2 + 8a2ccbd commit 18cf517

File tree

5 files changed

+76
-3
lines changed

5 files changed

+76
-3
lines changed

src/concurrency/fields.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ def _get_hash(self, instance):
333333
check_fields = instance._concurrencymeta.check_fields
334334
ignore_fields = instance._concurrencymeta.ignore_fields
335335

336-
if check_fields is None:
336+
if check_fields is None and ignore_fields is None:
337+
fields = sorted([f.name for f in instance._meta.get_fields()])
338+
elif check_fields is None:
337339
fields = sorted([f.name for f in instance._meta.get_fields()
338340
if f.name not in ignore_fields])
339341
else:
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import migrations, models
5+
from django.conf import settings
6+
import concurrency.fields
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13+
('demo', '0001_initial'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='ConditionalVersionModelWithoutMeta',
19+
fields=[
20+
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
21+
('version', concurrency.fields.ConditionalVersionField(default=1, help_text='record revision number')),
22+
('field1', models.CharField(unique=True, blank=True, max_length=30, null=True)),
23+
('field2', models.CharField(unique=True, blank=True, max_length=30, null=True)),
24+
('field3', models.CharField(unique=True, blank=True, max_length=30, null=True)),
25+
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)),
26+
],
27+
),
28+
]

tests/demoapp/demo/models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
__all__ = ['SimpleConcurrentModel', 'AutoIncConcurrentModel',
1212
'ProxyModel', 'InheritedModel', 'CustomSaveModel',
1313
'ConcreteModel', 'TriggerConcurrentModel',
14+
'ConditionalVersionModelWithoutMeta',
1415
]
1516

1617

@@ -210,3 +211,17 @@ class Meta:
210211

211212
class ConcurrencyMeta:
212213
check_fields = ['field1', 'field2', 'user']
214+
215+
216+
class ConditionalVersionModelWithoutMeta(models.Model):
217+
"""
218+
This model doesn't have ConcurrencyMeta defined.
219+
"""
220+
version = ConditionalVersionField()
221+
field1 = models.CharField(max_length=30, blank=True, null=True, unique=True)
222+
field2 = models.CharField(max_length=30, blank=True, null=True, unique=True)
223+
field3 = models.CharField(max_length=30, blank=True, null=True, unique=True)
224+
user = models.ForeignKey(User, null=True)
225+
226+
class Meta:
227+
app_label = 'demo'

tests/demoapp/demo/settings.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,6 @@
117117
else:
118118
DATABASES = {
119119
'default': {
120-
'ENGINE': 'django.db.backends.sqlite3'}}
120+
'ENGINE': 'django.db.backends.sqlite3',
121+
'NAME': dbname,
122+
}}

tests/test_conditional.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99
from concurrency.exceptions import RecordModifiedError
1010
from concurrency.utils import refetch
11-
from demo.models import ConditionalVersionModel
11+
from demo.models import (
12+
ConditionalVersionModel,
13+
ConditionalVersionModelWithoutMeta,
14+
)
1215

1316
logger = logging.getLogger(__name__)
1417

@@ -25,6 +28,15 @@ def instance(user):
2528
field2='1', field3='1')[0]
2629

2730

31+
@pytest.fixture
32+
def instance_no_meta(user):
33+
return ConditionalVersionModelWithoutMeta.objects.create(
34+
field1='1',
35+
user=user,
36+
field2='1', field3='1'
37+
)
38+
39+
2840
@pytest.mark.django_db
2941
def test_standard_save(instance):
3042
# only increment if checked field
@@ -74,3 +86,17 @@ def test_save_allowed(instance):
7486
batch_instance.field3 = 'aaaa'
7587
batch_instance.save()
7688
instance.save()
89+
90+
91+
@pytest.mark.django_db(transaction=True)
92+
def test_conflict_no_meta(instance_no_meta):
93+
# Scenario: batch change any field,
94+
# the user is NOT ALLOWED to save
95+
batch_instance = instance_no_meta.__class__.objects.get(pk=instance_no_meta.pk)
96+
assert batch_instance.version == instance_no_meta.version
97+
98+
batch_instance.field1 = 'aaaa'
99+
batch_instance.save()
100+
101+
with pytest.raises(RecordModifiedError):
102+
instance_no_meta.save()

0 commit comments

Comments
 (0)