Index: django/forms/models.py
===================================================================
--- django/forms/models.py	(revision 8445)
+++ django/forms/models.py	(working copy)
@@ -220,13 +220,23 @@
 
 def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
                        formfield_callback=lambda f: f.formfield()):
-    # HACK: we should be able to construct a ModelForm without creating
-    # and passing in a temporary inner class
-    class Meta:
-        pass
-    setattr(Meta, 'model', model)
-    setattr(Meta, 'fields', fields)
-    setattr(Meta, 'exclude', exclude)
+    import types
+    bases = ()
+    if hasattr(form, 'Meta'):
+        bases = (form.Meta, )
+    Meta = types.ClassType('Meta', bases, {})
+
+    form_model = getattr(Meta, 'model', None)
+    if form_model:
+        if form_model != model:
+            raise Exception('model %s does not match model %s for ModelForm %s' % 
+                (model, form_model, form))
+    else:
+        setattr(Meta, 'model', model)
+
+    if fields: setattr(Meta, 'fields', fields)
+    if exclude: setattr(Meta, 'exclude', exclude)
+
     class_name = model.__name__ + 'Form'
     return ModelFormMetaclass(class_name, (form,), {'Meta': Meta,
                               'formfield_callback': formfield_callback})
@@ -242,20 +252,14 @@
 
     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                  queryset=None, **kwargs):
-        self.queryset = queryset
-        defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
-        if self.max_num > 0:
-            qs = self.get_queryset()[:self.max_num]
-        else:
-            qs = self.get_queryset()
-        defaults['initial'] = [model_to_dict(obj) for obj in qs]
+        self.queryset = queryset or self.model._default_manager.get_query_set()
+            
+        defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix, 'initial': self.queryset}
         defaults.update(kwargs)
         super(BaseModelFormSet, self).__init__(**defaults)
 
     def get_queryset(self):
-        if self.queryset is not None:
-            return self.queryset
-        return self.model._default_manager.get_query_set()
+        return self.queryset
 
     def save_new(self, form, commit=True):
         """Saves and returns a new model instance for the given form."""
@@ -269,52 +273,34 @@
         """Saves model instances for every form, adding and changing instances
         as necessary, and returns the list of instances.
         """
+        self.changed_objects = []
+        self.deleted_objects = []
+        self.new_objects = []
         if not commit:
             self.saved_forms = []
             def save_m2m():
                 for form in self.saved_forms:
                     form.save_m2m()
             self.save_m2m = save_m2m
-        return self.save_existing_objects(commit) + self.save_new_objects(commit)
 
-    def save_existing_objects(self, commit=True):
-        self.changed_objects = []
-        self.deleted_objects = []
-        if not self.get_queryset():
-            return []
-
-        # Put the objects from self.get_queryset into a dict so they are easy to lookup by pk
-        existing_objects = {}
-        for obj in self.get_queryset():
-            existing_objects[obj.pk] = obj
         saved_instances = []
-        for form in self.initial_forms:
-            obj = existing_objects[form.cleaned_data[self.model._meta.pk.attname]]
+        for form in self.forms:
             if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
-                self.deleted_objects.append(obj)
-                obj.delete()
-            else:
-                if form.changed_data:
-                    self.changed_objects.append((obj, form.changed_data))
-                    saved_instances.append(self.save_existing(form, obj, commit=commit))
+                if form.instance:
+                    self.deleted_objects.append(obj)
+                    obj.delete()
+                else:
+                    continue
+            elif form.changed_data:
+                    if form.instance:
+                        self.changed_objects.append((form.instance, form.changed_data))
+                        saved_instances.append(form.save(commit=commit))
+                    else:
+                        self.new_objects.append(form.save(commit=commit))
                     if not commit:
                         self.saved_forms.append(form)
-        return saved_instances
+        return saved_instances + self.new_objects
 
-    def save_new_objects(self, commit=True):
-        self.new_objects = []
-        for form in self.extra_forms:
-            if not form.has_changed():
-                continue
-            # If someone has marked an add form for deletion, don't save the
-            # object.
-            if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
-                continue
-            self.new_objects.append(self.save_new(form, commit=commit))
-            if not commit:
-                self.saved_forms.append(form)
-        return self.new_objects
-
     def add_fields(self, form, index):
         """Add a hidden field for the object's primary key."""
         if self.model._meta.has_auto_field:
@@ -322,6 +308,23 @@
             form.fields[self._pk_field_name] = IntegerField(required=False, widget=HiddenInput)
         super(BaseModelFormSet, self).add_fields(form, index)
 
+    def _construct_form(self, i, **kwargs):
+        defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)}
+        if self.data or self.files:
+            defaults['data'] = self.data
+            defaults['files'] = self.files
+        # Allow extra forms to be empty.
+        if i >= self._initial_form_count:
+            defaults['empty_permitted'] = True
+        else:
+            defaults['instance'] = self.queryset[i]
+            
+        defaults.update(kwargs)
+        form = self.form(**defaults)
+        self.add_fields(form, i)
+        return form
+
+
 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
                          formset=BaseModelFormSet,
                          extra=1, can_delete=False, can_order=False,
