Index: django/newforms/models.py
===================================================================
--- django/newforms/models.py	(revision 6473)
+++ django/newforms/models.py	(working copy)
@@ -16,7 +16,7 @@
 __all__ = (
     'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
     'ModelChoiceField', 'ModelMultipleChoiceField', 'formset_for_model',
-    'inline_formset'
+    'formset_for_queryset', 'inline_formset'
 )
 
 def save_instance(form, instance, fields=None, fail_message='saved', commit=True):
@@ -240,12 +240,12 @@
     A ``FormSet`` attatched to a particular model or sequence of model instances.
     """
     model = None
+    queryset = None
 
-    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, instances=None):
-        self.instances = instances
+    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None):
         kwargs = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
-        if instances:
-            kwargs['initial'] = [initial_data(instance) for instance in instances]
+        if self.queryset:
+            kwargs['initial'] = [initial_data(instance) for instance in self.queryset]
         super(BaseModelFormSet, self).__init__(**kwargs)
 
     def save_new(self, form, commit=True):
@@ -261,11 +261,11 @@
         as necessary, and returns the list of instances.
         """
         saved_instances = []
-        # put self.instances into a dict so they are easy to lookup by pk
-        instances = {}
-        for instance in self.instances:
-            instances[instance._get_pk_val()] = instance
-        if self.instances:
+        if self.queryset:
+            # put self.instances into a dict so they are easy to lookup by pk
+            instances = {}
+            for instance in self.queryset:
+                instances[instance._get_pk_val()] = instance
             # update/save existing instances
             for form in self.change_forms:
                 instance = instances[form.cleaned_data[self.model._meta.pk.attname]]
@@ -292,20 +292,29 @@
     FormSet.model = model
     return FormSet
 
+def formset_for_queryset(queryset, form=BaseForm, formfield_callback=lambda f: f.formfield(), formset=BaseModelFormSet, extra=1, orderable=False, deletable=True, fields=None):
+    model = queryset.model
+    form = form_for_model(model, form=form, fields=fields, formfield_callback=formfield_callback)
+    FormSet = formset_for_form(form, formset, extra, orderable, deletable)
+    FormSet.model = model
+    FormSet.queryset = queryset
+    return FormSet
+
 class InlineFormset(BaseModelFormSet):
     """A formset for child objects related to a parent."""
     def __init__(self, instance=None, data=None, files=None):
         from django.db.models.fields.related import RelatedObject
         self.instance = instance
+        if self.instance:
+            self.queryset = self.get_queryset()
         # is there a better way to get the object descriptor?
         self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
-        super(InlineFormset, self).__init__(data, files, instances=self.get_inline_objects(), prefix=self.rel_name)
+        super(InlineFormset, self).__init__(data, files, prefix=self.rel_name)
+    
+    def get_queryset(self):
+        kwargs = {'%s__%s__exact' % (self.fk.name, self.fk.rel.get_related_field().name): self.instance._get_pk_val()}
+        return self.model._default_manager.filter(**kwargs)
 
-    def get_inline_objects(self):
-        if self.instance is None:
-            return []
-        return getattr(self.instance, self.rel_name).all()
-
     def save_new(self, form, commit=True):
         kwargs = {self.fk.get_attname(): self.instance._get_pk_val()}
         new_obj = self.model(**kwargs)
Index: tests/modeltests/model_formsets/__init__.py
===================================================================
Index: tests/modeltests/model_formsets/models.py
===================================================================
--- tests/modeltests/model_formsets/models.py	(revision 0)
+++ tests/modeltests/model_formsets/models.py	(revision 0)
@@ -0,0 +1,83 @@
+
+import datetime
+from django.db import models
+
+class Blog(models.Model):
+    title = models.CharField(max_length=100)
+    is_active = models.BooleanField()
+    
+    def __unicode__(self):
+        return self.title
+
+class Post(models.Model):
+    blog = models.ForeignKey(Blog)
+    title = models.CharField(max_length=100)
+    pub_date = models.DateTimeField(default=datetime.datetime.now)
+    
+    def __unicode__(self):
+        return self.title
+
+__test__ = {'API_TESTS': """
+>>> from django.newforms import formset_for_model, formset_for_queryset, inline_formset
+
+>>> Blog.objects.all()
+[]
+
+>>> BlogFormSet = formset_for_queryset(Blog.objects.all())
+>>> formset = BlogFormSet()
+>>> for form in formset.forms:
+...     print form
+<tr><th><label for="id_form-0-title">Title:</label></th><td><input id="id_form-0-title" type="text" name="form-0-title" maxlength="100" /></td></tr>
+<tr><th><label for="id_form-0-is_active">Is active:</label></th><td><input type="checkbox" name="form-0-is_active" id="id_form-0-is_active" /></td></tr>
+<tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>
+
+Create an actual blog object.
+
+>>> b1 = Blog(title=u'My First Blog')
+>>> b1.save()
+
+>>> BlogFormSet = formset_for_queryset(Blog.objects.all())
+>>> formset = BlogFormSet()
+>>> for form in formset.forms:
+...     print form
+<tr><th><label for="id_form-0-title">Title:</label></th><td><input id="id_form-0-title" type="text" name="form-0-title" value="My First Blog" maxlength="100" /></td></tr>
+<tr><th><label for="id_form-0-is_active">Is active:</label></th><td><input type="checkbox" name="form-0-is_active" id="id_form-0-is_active" /></td></tr>
+<tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr>
+<tr><th><label for="id_form-1-title">Title:</label></th><td><input id="id_form-1-title" type="text" name="form-1-title" maxlength="100" /></td></tr>
+<tr><th><label for="id_form-1-is_active">Is active:</label></th><td><input type="checkbox" name="form-1-is_active" id="id_form-1-is_active" /></td></tr>
+<tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /><input type="hidden" name="form-1-id" id="id_form-1-id" /></td></tr>
+
+Now POST some data and see if the instance was updated correctly.
+
+>>> data = {
+...     'form-COUNT': '2',
+...     'form-0-id': '1',
+...     'form-0-title': 'My First Blog',
+...     'form-0-DELETE': '',
+...     'form-1-id': '',
+...     'form-1-title': 'My Second Blog',
+...     'form-1-DELETE': '',
+... }
+>>> formset = BlogFormSet(data)
+>>> formset.is_valid()
+True
+>>> formset.save()
+[<Blog: My First Blog>, <Blog: My Second Blog>]
+
+Now lets create one post in each blog.
+
+>>> b1.post_set.add(Post(title=u'How to Pour a Guinness'))
+>>> b2 = Blog.objects.get(pk=2)
+>>> b2.post_set.add(Post(title=u'Bad Pigs! Why Your Bacon Tastes Bad.'))
+
+>>> PostFormSet = inline_formset(Blog, Post, extra=1)
+>>> formset = PostFormSet(b2)
+>>> for form in formset.forms:
+...     print form
+<tr><th><label for="id_post_set-0-title">Title:</label></th><td><input id="id_post_set-0-title" type="text" name="post_set-0-title" value="Bad Pigs! Why Your Bacon Tastes Bad." maxlength="100" /></td></tr>
+<tr><th><label for="id_post_set-0-pub_date">Pub date:</label></th><td><input type="text" name="post_set-0-pub_date" value="2007-10-11 00:42:31.209597" id="id_post_set-0-pub_date" /></td></tr>
+<tr><th><label for="id_post_set-0-DELETE">Delete:</label></th><td><input type="checkbox" name="post_set-0-DELETE" id="id_post_set-0-DELETE" /><input type="hidden" name="post_set-0-id" value="2" id="id_post_set-0-id" /></td></tr>
+<tr><th><label for="id_post_set-1-title">Title:</label></th><td><input id="id_post_set-1-title" type="text" name="post_set-1-title" maxlength="100" /></td></tr>
+<tr><th><label for="id_post_set-1-pub_date">Pub date:</label></th><td><input type="text" name="post_set-1-pub_date" id="id_post_set-1-pub_date" /></td></tr>
+<tr><th><label for="id_post_set-1-DELETE">Delete:</label></th><td><input type="checkbox" name="post_set-1-DELETE" id="id_post_set-1-DELETE" /><input type="hidden" name="post_set-1-id" id="id_post_set-1-id" /></td></tr>
+"""}
