From 5e06fa1469180909c51c07151692412269e51ea3 Mon Sep 17 00:00:00 2001 From: Vincent-Vega Date: Mon, 16 Jun 2014 11:47:45 +0400 Subject: [PATCH] Fixed #22745 -- Prevented reevaluation of ModelChoiceField's queryset when accesssing BoundField's attrs. Thanks Christian Schmitt for review. --- django/forms/forms.py | 4 ++++ tests/model_forms/tests.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/django/forms/forms.py b/django/forms/forms.py index c5d6b19267..a4db99526e 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -529,6 +529,10 @@ class BoundField(object): return len(list(self.__iter__())) def __getitem__(self, idx): + # Prevent unnecessary reevaluation when accessing BoundField's attrs + # from templates. + if not isinstance(idx, six.integer_types): + raise TypeError return list(self.__iter__())[idx] @property diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index 3efc724c38..e704c62d2e 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -13,6 +13,7 @@ from django.db import connection from django.db.models.query import EmptyQuerySet from django.forms.models import (construct_instance, fields_for_model, model_to_dict, modelform_factory, ModelFormMetaclass) +from django.template import Template, Context from django.test import TestCase, skipUnlessDBFeature from django.utils._os import upath from django.utils import six @@ -1466,6 +1467,21 @@ class ModelChoiceFieldTests(TestCase): self.assertTrue(field1 is not ModelChoiceForm.base_fields['category']) self.assertTrue(field1.widget.choices.field is field1) + def test_modelchoicefield_22745(self): + """ + #22745 -- Make sure that ModelChoiceField with RadioSelect widget + doesn't produce unnecessary db queries when accessing its BoundField's + attrs. + """ + class ModelChoiceForm(forms.Form): + category = forms.ModelChoiceField(Category.objects.all(), widget=forms.RadioSelect) + + form = ModelChoiceForm() + field = form['category'] # BoundField + template = Template('{{ field.name }}{{ field }}{{ field.help_text }}') + with self.assertNumQueries(1): + template.render(Context({'field': field})) + class ModelMultipleChoiceFieldTests(TestCase): def setUp(self): @@ -1604,6 +1620,21 @@ class ModelMultipleChoiceFieldTests(TestCase): self.assertTrue(form.is_valid()) self.assertTrue(form.has_changed()) + def test_model_multiple_choice_field_22745(self): + """ + #22745 -- Make sure that ModelMultipleChoiceField with + CheckboxSelectMultiple widget doesn't produce unnecessary db queries + when accessing its BoundField's attrs. + """ + class ModelMultipleChoiceForm(forms.Form): + categories = forms.ModelMultipleChoiceField(Category.objects.all(), widget=forms.CheckboxSelectMultiple) + + form = ModelMultipleChoiceForm() + field = form['categories'] # BoundField + template = Template('{{ field.name }}{{ field }}{{ field.help_text }}') + with self.assertNumQueries(1): + template.render(Context({'field': field})) + class ModelOneToOneFieldTests(TestCase): def test_modelform_onetoonefield(self):