diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index 9c2e88bee7..cb3126e6d7 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -6,6 +6,7 @@ from django.forms.fields import IntegerField, BooleanField
 from django.forms.util import ErrorList
 from django.forms.widgets import HiddenInput
 from django.utils.encoding import python_2_unicode_compatible
+from django.utils.functional import cached_property
 from django.utils.safestring import mark_safe
 from django.utils import six
 from django.utils.six.moves import xrange
@@ -55,8 +56,6 @@ class BaseFormSet(object):
         self.error_class = error_class
         self._errors = None
         self._non_form_errors = None
-        # construct the forms in the formset
-        self._construct_forms()
 
     def __str__(self):
         return self.as_table()
@@ -125,12 +124,14 @@ class BaseFormSet(object):
             initial_forms = len(self.initial) if self.initial else 0
         return initial_forms
 
-    def _construct_forms(self):
-        # instantiate all the forms and put them in self.forms
-        self.forms = []
+    @cached_property
+    def forms(self):
+        """
+        Instantiate forms at first property access.
+        """
         # DoS protection is included in total_form_count()
-        for i in xrange(self.total_form_count()):
-            self.forms.append(self._construct_form(i))
+        forms = [self._construct_form(i) for i in xrange(self.total_form_count())]
+        return forms
 
     def _construct_form(self, i, **kwargs):
         """
diff --git a/tests/forms_tests/tests/test_formsets.py b/tests/forms_tests/tests/test_formsets.py
index b26017bc78..41577e6049 100644
--- a/tests/forms_tests/tests/test_formsets.py
+++ b/tests/forms_tests/tests/test_formsets.py
@@ -1072,7 +1072,8 @@ ArticleFormSet = formset_factory(ArticleForm)
 
 class TestIsBoundBehavior(TestCase):
     def test_no_data_raises_validation_error(self):
-        self.assertRaises(ValidationError, ArticleFormSet, {})
+        with self.assertRaises(ValidationError):
+            ArticleFormSet({}).is_valid()
 
     def test_with_management_data_attrs_work_fine(self):
         data = {
diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py
index 62870c7462..43509c471f 100644
--- a/tests/model_formsets/tests.py
+++ b/tests/model_formsets/tests.py
@@ -8,7 +8,7 @@ from decimal import Decimal
 from django import forms
 from django.db import models
 from django.forms.models import (_get_foreign_key, inlineformset_factory,
-    modelformset_factory)
+    modelformset_factory, BaseModelFormSet)
 from django.test import TestCase, skipUnlessDBFeature
 from django.utils import six
 
@@ -386,6 +386,23 @@ class ModelFormsetTest(TestCase):
         formset = PostFormSet()
         self.assertFalse("subtitle" in formset.forms[0].fields)
 
+    def test_custom_queryset_init(self):
+        """
+        Test that a queryset can be overriden in the __init__ method.
+        https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#changing-the-queryset
+        """
+        author1 = Author.objects.create(name='Charles Baudelaire')
+        author2 = Author.objects.create(name='Paul Verlaine')
+
+        class BaseAuthorFormSet(BaseModelFormSet):
+            def __init__(self, *args, **kwargs):
+                super(BaseAuthorFormSet, self).__init__(*args, **kwargs)
+                self.queryset = Author.objects.filter(name__startswith='Charles')
+
+        AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
+        formset = AuthorFormSet()
+        self.assertEqual(len(formset.get_queryset()), 1)
+
     def test_model_inheritance(self):
         BetterAuthorFormSet = modelformset_factory(BetterAuthor, fields="__all__")
         formset = BetterAuthorFormSet()