summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2015-10-05 18:21:56 -0400
committerTim Graham <timograham@gmail.com>2015-10-05 19:19:09 -0400
commit6bc8bdf55ae71482ee3cd6c1ab157404c2e4ec5c (patch)
tree2dac9d9e3462becd63a22458621362b021d7fa9f
parent3429dfe11df8c7ac59255320c6d34609570345c3 (diff)
[1.9.x] Fixed #25496 -- Made ModelChoiceField respect prefetch_related().
Backport of 6afa6818fcf25665bbf61f0921c8c8c6fa8f223e from master
-rw-r--r--django/forms/models.py4
-rw-r--r--docs/releases/1.8.6.txt3
-rw-r--r--tests/model_forms/tests.py23
3 files changed, 28 insertions, 2 deletions
diff --git a/django/forms/models.py b/django/forms/models.py
index ac8bd1c860..938535bf6a 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -1102,7 +1102,9 @@ class ModelChoiceIterator(object):
def __iter__(self):
if self.field.empty_label is not None:
yield ("", self.field.empty_label)
- for obj in self.queryset.iterator():
+ # Can't use iterator() when queryset uses prefetch_related()
+ method = 'all' if self.queryset._prefetch_related_lookups else 'iterator'
+ for obj in getattr(self.queryset, method)():
yield self.choice(obj)
def __len__(self):
diff --git a/docs/releases/1.8.6.txt b/docs/releases/1.8.6.txt
index 6268bb3bbf..9292d7835b 100644
--- a/docs/releases/1.8.6.txt
+++ b/docs/releases/1.8.6.txt
@@ -9,4 +9,5 @@ Django 1.8.6 fixes several bugs in 1.8.5.
Bugfixes
========
-* ...
+* Fixed a regression causing ``ModelChoiceField`` to ignore
+ ``prefetch_related()`` on its queryset (:ticket:`25496`).
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index 98b9c1ad52..12401759bd 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -2285,6 +2285,29 @@ class OtherModelFormTests(TestCase):
with self.assertRaises(ValidationError):
f.fields['status'].clean('z')
+ def test_prefetch_related_queryset(self):
+ """
+ ModelChoiceField should respect a prefetch_related() on its queryset.
+ """
+ blue = Colour.objects.create(name='blue')
+ red = Colour.objects.create(name='red')
+ multicolor_item = ColourfulItem.objects.create()
+ multicolor_item.colours.add(blue, red)
+ red_item = ColourfulItem.objects.create()
+ red_item.colours.add(red)
+
+ class ColorModelChoiceField(forms.ModelChoiceField):
+ def label_from_instance(self, obj):
+ return ', '.join(c.name for c in obj.colours.all())
+
+ field = ColorModelChoiceField(ColourfulItem.objects.prefetch_related('colours'))
+ with self.assertNumQueries(4): # would be 5 if prefetch is ignored
+ self.assertEqual(tuple(field.choices), (
+ ('', '---------'),
+ (multicolor_item.pk, 'blue, red'),
+ (red_item.pk, 'red'),
+ ))
+
def test_foreignkeys_which_use_to_field(self):
apple = Inventory.objects.create(barcode=86, name='Apple')
Inventory.objects.create(barcode=22, name='Pear')