diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
index 9464107c7e..1db2174686 100644
--- a/django/contrib/admin/widgets.py
+++ b/django/contrib/admin/widgets.py
@@ -7,6 +7,7 @@ from django.utils.datastructures import MultiValueDict
from django.utils.text import capfirst, truncate_words
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
+from django.utils.encoding import force_unicode
from django.conf import settings
class FilteredSelectMultiple(forms.SelectMultiple):
@@ -135,6 +136,18 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
if value:
return [value]
return None
+
+ def _has_changed(self, initial, data):
+ if initial is None:
+ initial = []
+ if data is None:
+ data = []
+ if len(initial) != len(data):
+ return True
+ for pk1, pk2 in zip(initial, data):
+ if force_unicode(pk1) != force_unicode(pk2):
+ return True
+ return False
class RelatedFieldWidgetWrapper(object):
"""
diff --git a/tests/regressiontests/admin_widgets/models.py b/tests/regressiontests/admin_widgets/models.py
index 7207e8edd4..97e8f23bf9 100644
--- a/tests/regressiontests/admin_widgets/models.py
+++ b/tests/regressiontests/admin_widgets/models.py
@@ -66,6 +66,18 @@ Currently: test
Change: >> w = ManyToManyRawIdWidget(rel)
>>> print conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={}))
+>>> w._has_changed(None, None)
+False
+>>> w._has_changed([], None)
+False
+>>> w._has_changed(None, [u'1'])
+True
+>>> w._has_changed([1, 2], [u'1', u'2'])
+False
+>>> w._has_changed([1, 2], [u'1'])
+True
+>>> w._has_changed([1, 2], [u'1', u'3'])
+True
""" % {
'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX,