Przeglądaj źródła

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

Thanks Christian Schmitt for review.
Vincent-Vega 10 lat temu
rodzic
commit
5e06fa1469
2 zmienionych plików z 35 dodań i 0 usunięć
  1. 4 0
      django/forms/forms.py
  2. 31 0
      tests/model_forms/tests.py

+ 4 - 0
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

+ 31 - 0
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):