Make ``Formset.__getitem__`` O(1), rather than O(n). If you override ``__iter__`` you now need to also override ``__getitem__`` for consistant behavior. Thanks to Carl and Russ for the review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16770 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2011-09-10 01:53:56 +00:00
parent 5f287f75f2
commit 01b0eb50fd
3 changed files with 16 additions and 10 deletions

View File

@ -55,7 +55,7 @@ class BaseFormSet(StrAndUnicode):
def __getitem__(self, index): def __getitem__(self, index):
"""Returns the form at the given index, based on the rendering order""" """Returns the form at the given index, based on the rendering order"""
return list(self)[index] return self.forms[index]
def __len__(self): def __len__(self):
return len(self.forms) return len(self.forms)

View File

@ -49,6 +49,10 @@ they were created. The default formset iterator also renders the forms
in this order, but you can change this order by providing an alternate in this order, but you can change this order by providing an alternate
implementation for the :meth:`__iter__()` method. implementation for the :meth:`__iter__()` method.
Formsets can also be indexed into, which returns the corresponding form. If you
override ``__iter__``, you will need to also override ``__getitem__`` to have
matching behavior.
Using initial data with a formset Using initial data with a formset
--------------------------------- ---------------------------------

View File

@ -793,8 +793,10 @@ class FormsFormsetTestCase(TestCase):
# Formets can override the default iteration order # Formets can override the default iteration order
class BaseReverseFormSet(BaseFormSet): class BaseReverseFormSet(BaseFormSet):
def __iter__(self): def __iter__(self):
for form in reversed(self.forms): return reversed(self.forms)
yield form
def __getitem__(self, idx):
return super(BaseReverseFormSet, self).__getitem__(len(self) - idx - 1)
ReverseChoiceFormset = formset_factory(Choice, BaseReverseFormSet, extra=3) ReverseChoiceFormset = formset_factory(Choice, BaseReverseFormSet, extra=3)
reverse_formset = ReverseChoiceFormset() reverse_formset = ReverseChoiceFormset()
@ -911,12 +913,12 @@ class TestIsBoundBehavior(TestCase):
# The empty forms should be equal. # The empty forms should be equal.
self.assertEqual(empty_forms[0].as_p(), empty_forms[1].as_p()) self.assertEqual(empty_forms[0].as_p(), empty_forms[1].as_p())
class TestEmptyFormSet(TestCase): class TestEmptyFormSet(TestCase):
"Test that an empty formset still calls clean()" "Test that an empty formset still calls clean()"
def test_empty_formset_is_valid(self): def test_empty_formset_is_valid(self):
EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate) EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate)
formset = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 'form-TOTAL_FORMS':'0'},prefix="form") formset = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 'form-TOTAL_FORMS':'0'},prefix="form")
formset2 = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 'form-TOTAL_FORMS':'1', 'form-0-name':'bah' },prefix="form") formset2 = EmptyFsetWontValidateFormset(data={'form-INITIAL_FORMS':'0', 'form-TOTAL_FORMS':'1', 'form-0-name':'bah' },prefix="form")
self.assertFalse(formset.is_valid()) self.assertFalse(formset.is_valid())
self.assertFalse(formset2.is_valid()) self.assertFalse(formset2.is_valid())