Skip to content

Commit d6ba00d

Browse files
committed
add core._set_version() and VersionField._set_version_value()
1 parent 853b80b commit d6ba00d

File tree

5 files changed

+46
-34
lines changed

5 files changed

+46
-34
lines changed

concurrency/admin.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## -*- coding: utf-8 -*-
22
from __future__ import absolute_import, unicode_literals
33
import re
4-
from django.utils.encoding import force_text, force_unicode
4+
from django.utils.encoding import force_text
55
from django.contrib import admin, messages
66
from django.core.exceptions import ImproperlyConfigured, ValidationError
77
from django.db.models import Q
@@ -13,7 +13,8 @@
1313
from django.http import HttpResponse, HttpResponseRedirect
1414
from django.utils.translation import ungettext, ugettext as _
1515
from concurrency import forms
16-
from concurrency.api import get_revision_of_object, get_version_fieldname
16+
from concurrency import core
17+
from concurrency.api import get_revision_of_object
1718
from concurrency.config import conf, CONCURRENCY_LIST_EDITABLE_POLICY_SILENT
1819
from concurrency.exceptions import RecordModifiedError
1920
from concurrency.forms import ConcurrentForm, VersionWidget
@@ -160,7 +161,7 @@ def save_model(self, request, obj, form, change):
160161
if change:
161162
version = request.POST.get('_concurrency_version_{0.pk}'.format(obj), None)
162163
if version:
163-
setattr(obj, get_version_fieldname(obj), int(version))
164+
core._set_version(obj, version)
164165
super(ConcurrencyListEditableMixin, self).save_model(request, obj, form, change)
165166
except RecordModifiedError:
166167
self._concurrency_list_editable_errors.append(obj.pk)
@@ -169,35 +170,25 @@ def save_model(self, request, obj, form, change):
169170
else:
170171
raise
171172

172-
173-
class ConcurrentModelAdmin(ConcurrencyActionMixin,
174-
ConcurrencyListEditableMixin,
175-
admin.ModelAdmin):
176-
form = ConcurrentForm
177-
formfield_overrides = {forms.VersionField: {'widget': VersionWidget}}
178-
179173
def changelist_view(self, request, extra_context=None):
180174
self._concurrency_list_editable_errors = []
181-
return super(ConcurrentModelAdmin, self).changelist_view(request, extra_context)
182-
183-
def save_model(self, request, obj, form, change):
184-
return super(ConcurrentModelAdmin, self).save_model(request, obj, form, change)
175+
return super(ConcurrencyListEditableMixin, self).changelist_view(request, extra_context)
185176

186177
def log_change(self, request, object, message):
187178
if object.pk in self._concurrency_list_editable_errors:
188179
return
189-
super(ConcurrentModelAdmin, self).log_change(request, object, message)
180+
super(ConcurrencyListEditableMixin, self).log_change(request, object, message)
190181

191182
def log_deletion(self, request, object, object_repr):
192183
if object.pk in self._concurrency_list_editable_errors:
193184
return
194-
super(ConcurrentModelAdmin, self).log_deletion(request, object, object_repr)
185+
super(ConcurrencyListEditableMixin, self).log_deletion(request, object, object_repr)
195186

196187
def message_user(self, request, message, **kwargs):
197188
# This is ugly but we do not want to touch the changelist_view() code.
198189
opts = self.model._meta
199190
if self._concurrency_list_editable_errors:
200-
names = force_unicode(opts.verbose_name), force_unicode(opts.verbose_name_plural)
191+
names = force_text(opts.verbose_name), force_text(opts.verbose_name_plural)
201192
pattern = r"(?P<num>\d+) ({0}|{1})".format(*names)
202193
rex = re.compile(pattern)
203194
m = rex.match(message)
@@ -213,12 +204,19 @@ def message_user(self, request, message, **kwargs):
213204
"Records `{0}` have been modified and were not updated",
214205
concurrency_errros).format(ids))
215206
if updated_record == 1:
216-
name = force_unicode(opts.verbose_name)
207+
name = force_text(opts.verbose_name)
217208
else:
218-
name = force_unicode(opts.verbose_name_plural)
209+
name = force_text(opts.verbose_name_plural)
219210
message = ungettext("%(count)s %(name)s was changed successfully.",
220211
"%(count)s %(name)s were changed successfully.",
221212
updated_record) % {'count': updated_record,
222213
'name': name}
223214

224-
return super(ConcurrentModelAdmin, self).message_user(request, message, **kwargs)
215+
return super(ConcurrencyListEditableMixin, self).message_user(request, message, **kwargs)
216+
217+
218+
class ConcurrentModelAdmin(ConcurrencyActionMixin,
219+
ConcurrencyListEditableMixin,
220+
admin.ModelAdmin):
221+
form = ConcurrentForm
222+
formfield_overrides = {forms.VersionField: {'widget': VersionWidget}}

concurrency/api.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,16 @@
33
import logging
44
from contextlib import contextmanager
55
from django.core.exceptions import ImproperlyConfigured
6-
from concurrency.core import _select_lock, _wrap_model_save
6+
from concurrency.core import _select_lock, _wrap_model_save, get_version_fieldname
77
from concurrency.exceptions import RecordModifiedError
88

99
__all__ = ['apply_concurrency_check', 'concurrency_check', 'get_revision_of_object',
1010
'RecordModifiedError', 'disable_concurrency', 'disable_sanity_check',
11-
'get_object_with_version', 'get_version', 'is_changed']
11+
'get_object_with_version', 'get_version', 'is_changed', 'get_version_fieldname']
1212

1313
logger = logging.getLogger(__name__)
1414

1515

16-
def get_version_fieldname(obj):
17-
return obj.RevisionMetaInfo.field.attname
18-
19-
2016
def get_revision_of_object(obj):
2117
"""
2218
returns teh version of the passed object

concurrency/core.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from __future__ import absolute_import, unicode_literals
1+
from __future__ import absolute_import
22
import logging
33
from functools import update_wrapper
44
from django.db import connections, router
@@ -21,6 +21,20 @@ def emit(self, record):
2121
__all__ = []
2222

2323

24+
def get_version_fieldname(obj):
25+
return obj.RevisionMetaInfo.field.attname
26+
27+
28+
def _set_version(obj, version):
29+
"""
30+
Set the given version on the passed object
31+
32+
This function should be used with 'raw' values, any type conversion should be managed in
33+
VersionField._set_version_value(). This is needed for future enhancement of concurrency.
34+
"""
35+
obj._revisionmetainfo.field._set_version_value(obj, version)
36+
37+
2438
def _select_lock(model_instance, version_value=None):
2539
version_field = model_instance.RevisionMetaInfo.field
2640
value = version_value or getattr(model_instance, version_field.name)
@@ -49,7 +63,6 @@ def _wrap_model_save(model, force=False):
4963
old_save = getattr(model, 'save')
5064
setattr(model, 'save', _wrap_save(old_save))
5165
model.RevisionMetaInfo.versioned_save = True
52-
model._revisionmetainfo = RevisionMetaInfo()
5366

5467

5568
def _wrap_save(func):

concurrency/fields.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,15 @@ def contribute_to_class(self, cls, name):
4747
if hasattr(cls, 'RevisionMetaInfo'):
4848
return
4949
setattr(cls, 'RevisionMetaInfo', RevisionMetaInfo())
50+
#TODO: allow user customization of RevisionMetaInfo
51+
cls._revisionmetainfo = cls.RevisionMetaInfo
5052
_wrap_model_save(cls)
5153
cls.RevisionMetaInfo.field = self
5254
cls.RevisionMetaInfo.manually = self.manually
5355

56+
def _set_version_value(self, model_instance, value):
57+
setattr(model_instance, self.attname, int(value))
58+
5459

5560
class IntegerVersionField(VersionField):
5661
"""
@@ -68,7 +73,7 @@ def get_internal_type(self):
6873
def pre_save(self, model_instance, add):
6974
old_value = getattr(model_instance, self.attname, 0)
7075
value = max(int(old_value) + 1, (int(time.time() * 1000000) - OFFSET))
71-
setattr(model_instance, self.attname, value)
76+
self._set_version_value(model_instance, value)
7277
return value
7378

7479

@@ -84,7 +89,7 @@ def get_internal_type(self):
8489

8590
def pre_save(self, model_instance, add):
8691
value = int(getattr(model_instance, self.attname, 0)) + 1
87-
setattr(model_instance, self.attname, value)
92+
self._set_version_value(model_instance, value)
8893
return value
8994

9095

concurrency/tests/admin_list_editable.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import absolute_import, unicode_literals
33
from django.contrib.admin.models import LogEntry
44
from django.contrib.contenttypes.models import ContentType
5-
from django.utils.encoding import force_unicode
5+
from django.utils.encoding import force_text
66

77
from concurrency.tests.base import AdminTestCase, SENTINEL
88
from concurrency.tests.models import ListEditableConcurrentModel, NoActionsConcurrentModel
@@ -59,7 +59,7 @@ def test_message_user(self):
5959

6060
self.assertIn('Record with pk `1` has been modified and was not updated',
6161
messages)
62-
self.assertIn('1 %s was changed successfully.' % force_unicode(self.TARGET._meta.verbose_name),
62+
self.assertIn('1 %s was changed successfully.' % force_text(self.TARGET._meta.verbose_name),
6363
messages)
6464

6565
def test_message_user_no_changes(self):
@@ -72,9 +72,9 @@ def test_message_user_no_changes(self):
7272
form['form-0-dummy_char'] = 'CHAR1'
7373
res = form.submit('_save').follow()
7474

75-
messages = map(str, list(res.context['messages']))
75+
messages = list(map(str, list(res.context['messages'])))
7676

77-
self.assertIn('No %s were changed due conflict errors' % force_unicode(self.TARGET._meta.verbose_name),
77+
self.assertIn('No %s were changed due conflict errors' % force_text(self.TARGET._meta.verbose_name),
7878
messages)
7979
self.assertEqual(len(messages), 1)
8080

0 commit comments

Comments
 (0)