diff --git a/django/forms/models.py b/django/forms/models.py
index ecfdc92..88da1c3 100644
a
|
b
|
class ModelMultipleChoiceField(ModelChoiceField):
|
998 | 998 | if self.required and not value: |
999 | 999 | raise ValidationError(self.error_messages['required']) |
1000 | 1000 | elif not self.required and not value: |
1001 | | return [] |
| 1001 | return self.queryset.none() |
1002 | 1002 | if not isinstance(value, (list, tuple)): |
1003 | 1003 | raise ValidationError(self.error_messages['list']) |
1004 | 1004 | key = self.to_field_name or 'pk' |
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index 96f1be9..36db856 100644
a
|
b
|
example::
|
931 | 931 | .. class:: ModelMultipleChoiceField(**kwargs) |
932 | 932 | |
933 | 933 | * Default widget: ``SelectMultiple`` |
934 | | * Empty value: ``[]`` (an empty list) |
935 | | * Normalizes to: A list of model instances. |
| 934 | * Empty value: An empty ``QuerySet`` (self.queryset.none()) |
| 935 | * Normalizes to: A ``QuerySet`` of model instances. |
936 | 936 | * Validates that every id in the given list of values exists in the |
937 | 937 | queryset. |
938 | 938 | * Error message keys: ``required``, ``list``, ``invalid_choice``, |
diff --git a/tests/regressiontests/forms/models.py b/tests/regressiontests/forms/models.py
index 203980c..8e7bdb3 100644
a
|
b
|
class ChoiceFieldModel(models.Model):
|
57 | 57 | default=lambda: ChoiceOptionModel.objects.filter(name='default')) |
58 | 58 | multi_choice_int = models.ManyToManyField(ChoiceOptionModel, blank=False, related_name='multi_choice_int', |
59 | 59 | default=lambda: [1]) |
| 60 | multi_choice_optional = models.ManyToManyField(ChoiceOptionModel, blank=True, null=True, |
| 61 | related_name='multi_choice_optional') |
60 | 62 | |
61 | 63 | |
62 | 64 | class FileModel(models.Model): |
diff --git a/tests/regressiontests/forms/tests/models.py b/tests/regressiontests/forms/tests/models.py
index 3f548df..8be569a 100644
a
|
b
|
|
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 | import datetime |
3 | 3 | from django.core.files.uploadedfile import SimpleUploadedFile |
| 4 | from django.db.models.query import QuerySet |
4 | 5 | from django.forms import Form, ModelForm, FileField, ModelChoiceField |
5 | 6 | from django.test import TestCase |
6 | 7 | from regressiontests.forms.models import ChoiceModel, ChoiceOptionModel, ChoiceFieldModel, FileModel, Group, BoundaryModel, Defaults |
… |
… |
class TestTicket12510(TestCase):
|
28 | 29 | self.assertNumQueries(1, test) |
29 | 30 | |
30 | 31 | class ModelFormCallableModelDefault(TestCase): |
| 32 | def test_empty_queryset_return(self): |
| 33 | "If a model's ManyToManyField has blank=True and is saved with no data, a queryset is returned." |
| 34 | option = ChoiceOptionModel.objects.create(id=1, name='default') |
| 35 | form = ChoiceFieldForm({'multi_choice_optional': '', 'choice': option.id, 'choice_int': 1, |
| 36 | 'multi_choice': ['1'], 'multi_choice_int': [1]}) |
| 37 | self.assertEqual(form.is_valid(), True) |
| 38 | self.assertEqual(isinstance(form.cleaned_data['multi_choice_optional'], QuerySet), True) |
| 39 | # While we're at it, test whether a QuerySet is returned if there *is* a value. |
| 40 | self.assertEqual(isinstance(form.cleaned_data['multi_choice'], QuerySet), True) |
| 41 | |
31 | 42 | def test_no_empty_option(self): |
32 | 43 | "If a model's ForeignKey has blank=False and a default, no empty option is created (Refs #10792)." |
33 | 44 | option = ChoiceOptionModel.objects.create(name='default') |
… |
… |
class ModelFormCallableModelDefault(TestCase):
|
60 | 71 | <option value="1" selected="selected">ChoiceOption 1</option> |
61 | 72 | <option value="2">ChoiceOption 2</option> |
62 | 73 | <option value="3">ChoiceOption 3</option> |
63 | | </select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0" /> <span class="helptext"> Hold down "Control", or "Command" on a Mac, to select more than one.</span></p>""") |
| 74 | </select><input type="hidden" name="initial-multi_choice_int" value="1" id="initial-id_multi_choice_int_0" /> <span class="helptext"> Hold down "Control", or "Command" on a Mac, to select more than one.</span></p> |
| 75 | <p><label for="id_multi_choice_optional">Multi choice optional:</label> <select multiple="multiple" name="multi_choice_optional" id="id_multi_choice_optional"> |
| 76 | <option value="1">ChoiceOption 1</option> |
| 77 | <option value="2">ChoiceOption 2</option> |
| 78 | <option value="3">ChoiceOption 3</option> |
| 79 | </select> <span class="helptext"> Hold down "Control", or "Command" on a Mac, to select more than one.</span></p>""") |
64 | 80 | |
65 | 81 | def test_initial_instance_value(self): |
66 | 82 | "Initial instances for model fields may also be instances (refs #7287)" |
… |
… |
class ModelFormCallableModelDefault(TestCase):
|
93 | 109 | <option value="2" selected="selected">ChoiceOption 2</option> |
94 | 110 | <option value="3" selected="selected">ChoiceOption 3</option> |
95 | 111 | </select><input type="hidden" name="initial-multi_choice_int" value="2" id="initial-id_multi_choice_int_0" /> |
96 | | <input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1" /> <span class="helptext"> Hold down "Control", or "Command" on a Mac, to select more than one.</span></p>""") |
| 112 | <input type="hidden" name="initial-multi_choice_int" value="3" id="initial-id_multi_choice_int_1" /> <span class="helptext"> Hold down "Control", or "Command" on a Mac, to select more than one.</span></p> |
| 113 | <p><label for="id_multi_choice_optional">Multi choice optional:</label> <select multiple="multiple" name="multi_choice_optional" id="id_multi_choice_optional"> |
| 114 | <option value="1">ChoiceOption 1</option> |
| 115 | <option value="2">ChoiceOption 2</option> |
| 116 | <option value="3">ChoiceOption 3</option> |
| 117 | </select> <span class="helptext"> Hold down "Control", or "Command" on a Mac, to select more than one.</span></p>""") |
97 | 118 | |
98 | 119 | |
99 | 120 | |