mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.8.x] Fixed #25496 -- Made ModelChoiceField respect prefetch_related().
Backport of 6afa6818fc from master
			
			
This commit is contained in:
		| @@ -1092,15 +1092,17 @@ class ModelChoiceIterator(object): | |||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         if self.field.empty_label is not None: |         if self.field.empty_label is not None: | ||||||
|             yield ("", self.field.empty_label) |             yield ("", self.field.empty_label) | ||||||
|  |         method = 'all' if self.queryset._prefetch_related_lookups else 'iterator' | ||||||
|  |         queryset = getattr(self.queryset, method) | ||||||
|         if self.field.cache_choices: |         if self.field.cache_choices: | ||||||
|             if self.field.choice_cache is None: |             if self.field.choice_cache is None: | ||||||
|                 self.field.choice_cache = [ |                 self.field.choice_cache = [ | ||||||
|                     self.choice(obj) for obj in self.queryset.iterator() |                     self.choice(obj) for obj in queryset() | ||||||
|                 ] |                 ] | ||||||
|             for choice in self.field.choice_cache: |             for choice in self.field.choice_cache: | ||||||
|                 yield choice |                 yield choice | ||||||
|         else: |         else: | ||||||
|             for obj in self.queryset.iterator(): |             for obj in queryset(): | ||||||
|                 yield self.choice(obj) |                 yield self.choice(obj) | ||||||
|  |  | ||||||
|     def __len__(self): |     def __len__(self): | ||||||
|   | |||||||
| @@ -9,4 +9,5 @@ Django 1.8.6 fixes several bugs in 1.8.5. | |||||||
| Bugfixes | Bugfixes | ||||||
| ======== | ======== | ||||||
|  |  | ||||||
| * ... | * Fixed a regression causing ``ModelChoiceField`` to ignore | ||||||
|  |   ``prefetch_related()`` on its queryset (:ticket:`25496`). | ||||||
|   | |||||||
| @@ -2203,6 +2203,29 @@ class OtherModelFormTests(TestCase): | |||||||
|         with self.assertRaises(ValidationError): |         with self.assertRaises(ValidationError): | ||||||
|             f.fields['status'].clean('z') |             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): |     def test_foreignkeys_which_use_to_field(self): | ||||||
|         apple = Inventory.objects.create(barcode=86, name='Apple') |         apple = Inventory.objects.create(barcode=86, name='Apple') | ||||||
|         Inventory.objects.create(barcode=22, name='Pear') |         Inventory.objects.create(barcode=22, name='Pear') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user