Index: django/contrib/admin/helpers.py
===================================================================
--- django/contrib/admin/helpers.py	(revision 12761)
+++ django/contrib/admin/helpers.py	(working copy)
@@ -1,6 +1,6 @@
 from django import forms
 from django.conf import settings
-from django.contrib.admin.util import flatten_fieldsets, lookup_field
+from django.contrib.admin.util import flatten_fieldsets, lookup_field, quote
 from django.contrib.admin.util import display_for_field, label_for_field
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ObjectDoesNotExist
@@ -11,8 +11,8 @@
 from django.utils.html import escape, conditional_escape
 from django.utils.safestring import mark_safe
 from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse, NoReverseMatch
 
-
 ACTION_CHECKBOX_NAME = '_selected_action'
 
 class ActionForm(forms.Form):
@@ -231,6 +231,18 @@
         if original is not None:
             self.original_content_type_id = ContentType.objects.get_for_model(original).pk
         self.show_url = original and hasattr(original, 'get_absolute_url')
+        if original is not None and model_admin is not None:
+            if original.__class__ in model_admin.admin_site._registry:
+                try:
+                    view_name = '%s:%s_%s_change' % (
+                        self.model_admin.admin_site.name,
+                        original._meta.app_label,
+                        original._meta.object_name.lower())
+                    self.admin_url = reverse(
+                        view_name, None, (quote(original._get_pk_val()),))
+                except NoReverseMatch:
+                    # should not happen, but fail silently just in case
+                    self.admin_url = None
         super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields,
             readonly_fields)
 
Index: django/contrib/admin/templates/admin/edit_inline/stacked.html
===================================================================
--- django/contrib/admin/templates/admin/edit_inline/stacked.html	(revision 12761)
+++ django/contrib/admin/templates/admin/edit_inline/stacked.html	(working copy)
@@ -6,7 +6,8 @@
 
 {% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}{% if not forloop.last %}{{ forloop.counter }}{% else %}-empty{% endif %}">
   <h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;<span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %}#{{ forloop.counter }}{% endif %}</span>
-    {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
+    {% if inline_admin_form.admin_url %}<a href="{{ inline_admin_form.admin_url }}">[ {% trans "Edit" %} ]</a>{% endif %}
+    {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">[ {% trans "View on site" %} ]</a>{% endif %}
     {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
   </h3>
   {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}
Index: django/contrib/admin/templates/admin/edit_inline/tabular.html
===================================================================
--- django/contrib/admin/templates/admin/edit_inline/tabular.html	(revision 12761)
+++ django/contrib/admin/templates/admin/edit_inline/tabular.html	(working copy)
@@ -25,7 +25,8 @@
         <td class="original">
           {% if inline_admin_form.original or inline_admin_form.show_url %}<p>
           {% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
-          {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
+          {% if inline_admin_form.admin_url %}<a href="{{ inline_admin_form.admin_url }}">[ {% trans "Edit" %} ]</a>{% endif %}
+          {% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">[ {% trans "View on site" %} ]</a>{% endif %}
             </p>{% endif %}
           {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
           {{ inline_admin_form.fk_field.field }}
Index: tests/regressiontests/admin_inlines/tests.py
===================================================================
--- tests/regressiontests/admin_inlines/tests.py	(revision 12761)
+++ tests/regressiontests/admin_inlines/tests.py	(working copy)
@@ -2,6 +2,7 @@
 
 # local test models
 from models import Holder, Inner, InnerInline
+from models import Household, Person, Phone
 
 class TestInline(TestCase):
     fixtures = ['admin-views-users.xml']
@@ -28,3 +29,47 @@
         actual = inner_formset.can_delete
         self.assertEqual(expected, actual, 'can_delete must be equal')
 
+        
+class TestAdminURL(TestCase):
+    fixtures = ['admin-views-users.xml']
+    
+    def get_admin_url(self, obj):
+        return '/test_admin/admin/admin_inlines/%s/%i/' % (
+            obj.__class__.__name__.lower(), obj.id)
+        
+    def setUp(self):
+        self.household = Household.objects.create()
+        self.person = Person.objects.create(household=self.household)
+        self.phone = Phone.objects.create(household=self.household)
+
+        result = self.client.login(username='super', password='secret')
+        self.failUnlessEqual(result, True)
+        
+    def tearDown(self):
+        self.client.logout()
+
+    def test_admin_url(self):
+        """
+        admin_url should be set for admin-registered inline models only.
+
+        Also check to ensure URLs look correct and only set on bound forms.
+        """
+        response = self.client.get(self.get_admin_url(self.household))
+        for inline_admin_fset in response.context[-1]['inline_admin_formsets']:
+            for inline_admin_form in inline_admin_fset:
+                if inline_admin_form.form._meta.model != Person:
+                    self.assertFalse(hasattr(inline_admin_form, 'admin_url'),
+                                     'admin_url set with unregistered model')
+                elif not inline_admin_form.original:
+                    self.assertFalse(hasattr(inline_admin_form, 'admin_url'),
+                                     'admin_url set on unbound form!')
+                else:
+                    self.assertTrue(hasattr(inline_admin_form, 'admin_url'),
+                                    'admin_url not set')
+                    self.assertEqual(inline_admin_form.original, self.person,
+                                     'original is not expected object')
+                    self.assertEqual(
+                        inline_admin_form.admin_url,
+                        self.get_admin_url(inline_admin_form.original),
+                        'admin_url appears incorrect')
+
Index: tests/regressiontests/admin_inlines/models.py
===================================================================
--- tests/regressiontests/admin_inlines/models.py	(revision 12761)
+++ tests/regressiontests/admin_inlines/models.py	(working copy)
@@ -48,6 +48,30 @@
 # Test bug #12561
 admin.site.register(Holder, inlines=[InnerInline])
 
+
+# Test InlineAdminForm.admin_url:
+
+class Household(models.Model):
+    pass
+
+class Person(models.Model):
+    household = models.ForeignKey(Household)
+
+class Phone(models.Model):
+    household = models.ForeignKey(Household)
+
+class PersonInline(admin.StackedInline):
+    model = Person
+    extra = 1
+
+class PhoneInline(admin.StackedInline):
+    model = Phone
+    extra = 1
+    
+admin.site.register(Household, inlines=[PersonInline, PhoneInline])
+admin.site.register(Person)
+# (Phone not registered)
+
 __test__ = {'API_TESTS': """
 
 # Regression test for #9362
 
