Fixed #22745 -- Prevented reevaluation of ModelChoiceField's queryset when accesssing BoundField's attrs.

Thanks Christian Schmitt for review.
This commit is contained in:
Vincent-Vega 2014-06-16 11:47:45 +04:00 committed by Tim Graham
parent 399cf303cb
commit 5e06fa1469
2 changed files with 35 additions and 0 deletions

View File

@ -529,6 +529,10 @@ class BoundField(object):
return len(list(self.__iter__())) return len(list(self.__iter__()))
def __getitem__(self, idx): 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] return list(self.__iter__())[idx]
@property @property

View File

@ -13,6 +13,7 @@ from django.db import connection
from django.db.models.query import EmptyQuerySet from django.db.models.query import EmptyQuerySet
from django.forms.models import (construct_instance, fields_for_model, from django.forms.models import (construct_instance, fields_for_model,
model_to_dict, modelform_factory, ModelFormMetaclass) model_to_dict, modelform_factory, ModelFormMetaclass)
from django.template import Template, Context
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase, skipUnlessDBFeature
from django.utils._os import upath from django.utils._os import upath
from django.utils import six from django.utils import six
@ -1466,6 +1467,21 @@ class ModelChoiceFieldTests(TestCase):
self.assertTrue(field1 is not ModelChoiceForm.base_fields['category']) self.assertTrue(field1 is not ModelChoiceForm.base_fields['category'])
self.assertTrue(field1.widget.choices.field is field1) 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): class ModelMultipleChoiceFieldTests(TestCase):
def setUp(self): def setUp(self):
@ -1604,6 +1620,21 @@ class ModelMultipleChoiceFieldTests(TestCase):
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
self.assertTrue(form.has_changed()) 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): class ModelOneToOneFieldTests(TestCase):
def test_modelform_onetoonefield(self): def test_modelform_onetoonefield(self):