diff --git a/django/forms/models.py b/django/forms/models.py index e9b71ccf262..0913a4e8b80 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -1033,6 +1033,8 @@ class ModelMultipleChoiceField(ModelChoiceField): return qs def prepare_value(self, value): - if hasattr(value, '__iter__') and not isinstance(value, six.text_type): + if (hasattr(value, '__iter__') and + not isinstance(value, six.text_type) and + not hasattr(value, '_meta')): return [super(ModelMultipleChoiceField, self).prepare_value(v) for v in value] return super(ModelMultipleChoiceField, self).prepare_value(value) diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 132da2d3188..383a10584b5 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -263,3 +263,18 @@ class FlexibleDatePost(models.Model): slug = models.CharField(max_length=50, unique_for_year='posted', blank=True) subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True) posted = models.DateField(blank=True, null=True) + +@python_2_unicode_compatible +class Colour(models.Model): + name = models.CharField(max_length=50) + + def __iter__(self): + for number in xrange(5): + yield number + + def __str__(self): + return self.name + +class ColourfulItem(models.Model): + name = models.CharField(max_length=50) + colours = models.ManyToManyField(Colour) diff --git a/tests/modeltests/model_forms/tests.py b/tests/modeltests/model_forms/tests.py index 47d72abdc2c..a401b16b093 100644 --- a/tests/modeltests/model_forms/tests.py +++ b/tests/modeltests/model_forms/tests.py @@ -19,7 +19,8 @@ from .models import (Article, ArticleStatus, BetterWriter, BigInt, Book, Category, CommaSeparatedInteger, CustomFieldForExclusionModel, DerivedBook, DerivedPost, ExplicitPK, FlexibleDatePost, ImprovedArticle, ImprovedArticleWithParentLink, Inventory, Post, Price, - Product, TextFile, Writer, WriterProfile, test_images) + Product, TextFile, Writer, WriterProfile, Colour, ColourfulItem, + test_images) if test_images: from .models import ImageFile, OptionalImageFile @@ -174,6 +175,10 @@ class PriceFormWithoutQuantity(forms.ModelForm): model = Price exclude = ('quantity',) +class ColourfulItemForm(forms.ModelForm): + class Meta: + model = ColourfulItem + class ModelFormBaseTest(TestCase): def test_base_form(self): @@ -1515,3 +1520,12 @@ class OldFormForXTests(TestCase): ['name']) self.assertHTMLEqual(six.text_type(CustomFieldForExclusionForm()), '''''') + + def test_iterable_model_m2m(self) : + colour = Colour.objects.create(name='Blue') + form = ColourfulItemForm() + self.maxDiff = 1024 + self.assertHTMLEqual(form.as_p(), """

+

Hold down "Control", or "Command" on a Mac, to select more than one.

""")