diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index f5f6256..1a0ec54 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -3,7 +3,7 @@ from django import forms
 from django.conf import settings
 from django.forms.formsets import all_valid
 from django.forms.models import (modelform_factory, modelformset_factory,
-    inlineformset_factory, BaseInlineFormSet)
+    inlineformset_factory, BaseInlineFormSet, model_to_dict)
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.admin import widgets, helpers
 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict
@@ -383,6 +383,9 @@ class ModelAdmin(BaseModelAdmin):
             url(r'^(.+)/delete/$',
                 wrap(self.delete_view),
                 name='%s_%s_delete' % info),
+            url(r'^(.+)/clone/$',
+                wrap(self.clone_view),
+                name='%s_%s_clone' % info),
             url(r'^(.+)/$',
                 wrap(self.change_view),
                 name='%s_%s_change' % info),
@@ -950,7 +953,6 @@ class ModelAdmin(BaseModelAdmin):
                     prefix = "%s-%s" % (prefix, prefixes[prefix])
                 formset = FormSet(data=request.POST, files=request.FILES,
                                   instance=new_object,
-                                  save_as_new="_saveasnew" in request.POST,
                                   prefix=prefix, queryset=inline.queryset(request))
                 formsets.append(formset)
             if all_valid(formsets) and form_validated:
@@ -1009,6 +1011,88 @@ class ModelAdmin(BaseModelAdmin):
         context.update(extra_context or {})
         return self.render_change_form(request, context, form_url=form_url, add=True)
 
+
+    @csrf_protect_m
+    @transaction.commit_on_success
+    def clone_view(self, request, object_id, form_url='', extra_context=None):
+        model = self.model
+        opts = model._meta
+
+        if not self.has_add_permission(request):
+            raise PermissionDenied
+
+        original_obj = self.get_object(request, unquote(object_id))
+
+        ModelForm = self.get_form(request)
+        formsets = []
+        inline_instances = self.get_inline_instances(request)
+        if request.method == 'POST':
+            form = ModelForm(request.POST, request.FILES)
+            if form.is_valid():
+                new_object = self.save_form(request, form, change=False)
+                form_validated = True
+            else:
+                form_validated = False
+                new_object = self.model()
+            prefixes = {}
+            for FormSet, inline in zip(self.get_formsets(request), inline_instances):
+                prefix = FormSet.get_default_prefix()
+                prefixes[prefix] = prefixes.get(prefix, 0) + 1
+                if prefixes[prefix] != 1 or not prefix:
+                    prefix = "%s-%s" % (prefix, prefixes[prefix])
+                formset = FormSet(data=request.POST, files=request.FILES,
+                                  instance=new_object,
+                                  prefix=prefix, queryset=inline.queryset(request))
+                formsets.append(formset)
+            if all_valid(formsets) and form_validated:
+                self.save_model(request, new_object, form, False)
+                self.save_related(request, form, formsets, False)
+                self.log_addition(request, new_object)
+                return self.response_add(request, new_object)
+        else:
+            initial = model_to_dict(original_obj)
+            form = ModelForm(initial=initial)
+            prefixes = {}
+            for FormSet, inline in zip(self.get_formsets(request, original_obj), inline_instances):
+                prefix = FormSet.get_default_prefix()
+                prefixes[prefix] = prefixes.get(prefix, 0) + 1
+                if prefixes[prefix] != 1 or not prefix:
+                    prefix = "%s-%s" % (prefix, prefixes[prefix])
+                formset = FormSet(instance=original_obj,
+                                  prefix=prefix,
+                                  save_as_new=True,
+                                  queryset=inline.queryset(request))
+                formsets.append(formset)
+
+        admin_form = helpers.AdminForm(form, list(self.get_fieldsets(request)),
+            self.get_prepopulated_fields(request),
+            self.get_readonly_fields(request),
+            model_admin=self)
+        media = self.media + admin_form.media
+
+        inline_admin_formsets = []
+        for inline, formset in zip(inline_instances, formsets):
+            fieldsets = list(inline.get_fieldsets(request, original_obj))
+            readonly = list(inline.get_readonly_fields(request, original_obj))
+            prepopulated = dict(inline.get_prepopulated_fields(request, original_obj))
+            inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
+                fieldsets, prepopulated, readonly, model_admin=self)
+            inline_admin_formsets.append(inline_admin_formset)
+            media = media + inline_admin_formset.media
+
+        context = {
+            'title': _('Add %s') % force_unicode(opts.verbose_name),
+            'adminform': admin_form,
+            'is_popup': "_popup" in request.REQUEST,
+            'show_delete': False,
+            'media': media,
+            'inline_admin_formsets': inline_admin_formsets,
+            'errors': helpers.AdminErrorList(form, formsets),
+            'app_label': opts.app_label,
+        }
+        context.update(extra_context or {})
+        return self.render_change_form(request, context, form_url=form_url, add=True)
+
     @csrf_protect_m
     @transaction.commit_on_success
     def change_view(self, request, object_id, form_url='', extra_context=None):
diff --git a/django/contrib/admin/templates/admin/submit_line.html b/django/contrib/admin/templates/admin/submit_line.html
index d6f854a..78bc255 100644
--- a/django/contrib/admin/templates/admin/submit_line.html
+++ b/django/contrib/admin/templates/admin/submit_line.html
@@ -2,7 +2,7 @@
 <div class="submit-row">
 {% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" {{ onclick_attrib }}/>{% endif %}
 {% if show_delete_link %}<p class="deletelink-box"><a href="delete/" class="deletelink">{% trans "Delete" %}</a></p>{% endif %}
-{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" {{ onclick_attrib }}/>{%endif%}
+{% if show_save_as_new %}<p><a href="clone/">"{% trans 'Save as new' %}"</a></p>{%endif%}
 {% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" {{ onclick_attrib }} />{% endif %}
 {% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" {{ onclick_attrib }}/>{% endif %}
 </div>
diff --git a/django/forms/models.py b/django/forms/models.py
index cd8f027..6961eed 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -682,6 +682,7 @@ class BaseInlineFormSet(BaseModelFormSet):
     """A formset for child objects related to a parent."""
     def __init__(self, data=None, files=None, instance=None,
                  save_as_new=False, prefix=None, queryset=None, **kwargs):
+
         from django.db.models.fields.related import RelatedObject
         if instance is None:
             self.instance = self.fk.rel.to()
@@ -693,25 +694,25 @@ class BaseInlineFormSet(BaseModelFormSet):
         if queryset is None:
             queryset = self.model._default_manager
         qs = queryset.filter(**{self.fk.name: self.instance})
+
+        initial = []
+        if save_as_new:
+            for obj in qs:
+                initial.append(model_to_dict(obj, exclude=[self.fk.name,
+                                                           self.instance._meta.pk.name]))
+            # make sure original instance won't be reused
+            self.instance = self.fk.rel.to()
+
         super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
-                                                queryset=qs, **kwargs)
+                                                queryset=qs, initial=initial, **kwargs)
 
     def initial_form_count(self):
         if self.save_as_new:
             return 0
         return super(BaseInlineFormSet, self).initial_form_count()
 
-
     def _construct_form(self, i, **kwargs):
         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
-        if self.save_as_new:
-            # Remove the primary key from the form's data, we are only
-            # creating new instances
-            form.data[form.add_prefix(self._pk_field.name)] = None
-
-            # Remove the foreign key from the form's data
-            form.data[form.add_prefix(self.fk.name)] = None
-
         # Set the fk value here so that the form can do it's validation.
         setattr(form.instance, self.fk.get_attname(), self.instance.pk)
         return form
