11## -*- coding: utf-8 -*-
22from __future__ import absolute_import , unicode_literals
3- from django .utils .encoding import force_text
3+ import re
4+ from django .utils .encoding import force_text , force_unicode
45from django .contrib import admin , messages
56from django .core .exceptions import ImproperlyConfigured , ValidationError
67from django .db .models import Q
1011from django .utils .safestring import mark_safe
1112from django .contrib .admin import helpers
1213from django .http import HttpResponse , HttpResponseRedirect
13- from django .utils .translation import ugettext as _
14+ from django .utils .translation import ungettext , ugettext as _
1415from concurrency import forms
1516from concurrency .api import get_revision_of_object , get_version_fieldname
1617from concurrency .config import conf , CONCURRENCY_LIST_EDITABLE_POLICY_SILENT
@@ -162,8 +163,9 @@ def save_model(self, request, obj, form, change):
162163 setattr (obj , get_version_fieldname (obj ), int (version ))
163164 super (ConcurrencyListEditableMixin , self ).save_model (request , obj , form , change )
164165 except RecordModifiedError :
166+ self ._concurrency_list_editable_errors .append (obj .pk )
165167 if self .list_editable_policy == CONCURRENCY_LIST_EDITABLE_POLICY_SILENT :
166- messages . error ( request , _ ( "Record with pk `{0.pk}` has been modified and was not updated" ). format ( obj ))
168+ pass
167169 else :
168170 raise
169171
@@ -174,5 +176,49 @@ class ConcurrentModelAdmin(ConcurrencyActionMixin,
174176 form = ConcurrentForm
175177 formfield_overrides = {forms .VersionField : {'widget' : VersionWidget }}
176178
179+ def changelist_view (self , request , extra_context = None ):
180+ self ._concurrency_list_editable_errors = []
181+ return super (ConcurrentModelAdmin , self ).changelist_view (request , extra_context )
182+
177183 def save_model (self , request , obj , form , change ):
178184 return super (ConcurrentModelAdmin , self ).save_model (request , obj , form , change )
185+
186+ def log_change (self , request , object , message ):
187+ if object .pk in self ._concurrency_list_editable_errors :
188+ return
189+ super (ConcurrentModelAdmin , self ).log_change (request , object , message )
190+
191+ def log_deletion (self , request , object , object_repr ):
192+ if object .pk in self ._concurrency_list_editable_errors :
193+ return
194+ super (ConcurrentModelAdmin , self ).log_deletion (request , object , object_repr )
195+
196+ def message_user (self , request , message , ** kwargs ):
197+ # This is ugly but we do not want to touch the changelist_view() code.
198+ opts = self .model ._meta
199+ if self ._concurrency_list_editable_errors :
200+ names = force_unicode (opts .verbose_name ), force_unicode (opts .verbose_name_plural )
201+ pattern = ur"(?P<num>\d+) ({0}|{1})" .format (* names )
202+ rex = re .compile (pattern )
203+ m = rex .match (message )
204+ concurrency_errros = len (self ._concurrency_list_editable_errors )
205+ if m :
206+ updated_record = int (m .group ('num' )) - len (self ._concurrency_list_editable_errors )
207+ if updated_record == 0 :
208+ message = _ ("No %(name)s were changed due conflict errors" % {'name' : names [0 ]})
209+ else :
210+ ids = "," .join (map (str , self ._concurrency_list_editable_errors ))
211+ messages .error (request ,
212+ ungettext ("Record with pk `{0}` has been modified and was not updated" ,
213+ "Records `{0}` have been modified and were not updated" ,
214+ concurrency_errros ).format (ids ))
215+ if updated_record == 1 :
216+ name = force_unicode (opts .verbose_name )
217+ else :
218+ name = force_unicode (opts .verbose_name_plural )
219+ message = ungettext ("%(count)s %(name)s was changed successfully." ,
220+ "%(count)s %(name)s were changed successfully." ,
221+ updated_record ) % {'count' : updated_record ,
222+ 'name' : name }
223+
224+ return super (ConcurrentModelAdmin , self ).message_user (request , message , ** kwargs )
0 commit comments