Index: django/contrib/admin/options.py
===================================================================
--- django/contrib/admin/options.py	(revision 16669)
+++ django/contrib/admin/options.py	(working copy)
@@ -5,12 +5,13 @@
     inlineformset_factory, BaseInlineFormSet)
 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
+from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict, obj_label
 from django.contrib.admin.templatetags.admin_static import static
 from django.contrib import messages
 from django.views.decorators.csrf import csrf_protect
 from django.core.exceptions import PermissionDenied, ValidationError
 from django.core.paginator import Paginator
+from django.core.urlresolvers import reverse
 from django.db import models, transaction, router
 from django.db.models.related import RelatedObject
 from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
@@ -801,6 +802,13 @@
                 return HttpResponseRedirect(request.path + "?_popup=1")
             else:
                 return HttpResponseRedirect(request.path)
+        elif "_popup" in request.POST:
+            # object changed via raw id link popup
+            obj_id = repr(force_unicode(obj._get_pk_val()))[1:]
+            obj_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.object_name.lower()), args=(obj.pk,), current_app=self.admin_site.name)
+            label = obj_label(obj).replace("&#39;", r"\'")
+            return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup('
+            "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label))
         elif "_saveasnew" in request.POST:
             msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj}
             self.message_user(request, msg)
Index: django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
===================================================================
--- django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js	(revision 16669)
+++ django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js	(working copy)
@@ -11,6 +11,15 @@
     return text;
 }
 
+function html_escape(text) {
+    text = text.replace(/&/g, '&amp;');
+    text = text.replace(/</g, '&lt;');
+    text = text.replace(/>/g, '&gt;');
+    text = text.replace(/"/g, '&quot;');
+    text = text.replace(/'/g, '&#39;');
+    return text;
+}
+
 // IE doesn't accept periods or dashes in the window name, but the element IDs
 // we use to generate popup window names may contain them, therefore we map them
 // to allowed characters in a reversible way so that we can locate the correct 
@@ -27,49 +36,66 @@
     return text;
 }
 
+function getAdminMediaPrefix() {
+    // Copy-paste from DateTimeShortcuts.js.
+        if (window.__admin_media_prefix__ != undefined) {
+        return window.__admin_media_prefix__;
+    } else {
+        return '/missing-admin-media-prefix/';
+    }
+}
+
+var CLEAR_RAW_ID = '<a href="#" onclick="return clearRawId(this);">' +
+'<img src="' + getAdminMediaPrefix() + 'img/icon_deletelink.gif" ' +
+'width="10" height="10" alt="Clear" title="Clear" /></a>';
+
+// FIXME: the following produce 'gettext is not defined' errors in FireBug.
+// Needs to be tracked down.
+// (jsi18n is generally included before this in admin templates)
+//
+// 'width="10" height="10" alt="' + gettext('Clear') + '" title="' +
+// gettext('Clear') + '" /></a>';
+
+function showRelatedObjectPopup(triggeringLink) {
+    var name = triggeringLink.parentNode.id.replace(/^view_lookup_/, '');
+    name = id_to_windowname(name);
+    return openPopupWindow(triggeringLink.href, '_popup', name);
+}
+
 function showRelatedObjectLookupPopup(triggeringLink) {
     var name = triggeringLink.id.replace(/^lookup_/, '');
     name = id_to_windowname(name);
-    var href;
-    if (triggeringLink.href.search(/\?/) >= 0) {
-        href = triggeringLink.href + '&pop=1';
-    } else {
-        href = triggeringLink.href + '?pop=1';
-    }
-    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
-    win.focus();
-    return false;
+    return openPopupWindow(triggeringLink.href, 'pop', name);
 }
 
-function dismissRelatedLookupPopup(win, chosenId) {
+function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) {
     var name = windowname_to_id(win.name);
     var elem = document.getElementById(name);
+    var nameElem = document.getElementById("view_lookup_" + name);
     if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
         elem.value += ',' + chosenId;
     } else {
         document.getElementById(name).value = chosenId;
     }
+    if (nameElem) {
+      nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' +
+       'onclick="return showRelatedObjectPopup(this);">' +
+        html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID;
+    }
     win.close();
 }
 
 function showAddAnotherPopup(triggeringLink) {
     var name = triggeringLink.id.replace(/^add_/, '');
     name = id_to_windowname(name);
-    href = triggeringLink.href
-    if (href.indexOf('?') == -1) {
-        href += '?_popup=1';
-    } else {
-        href  += '&_popup=1';
-    }
-    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
-    win.focus();
-    return false;
+    return openPopupWindow(triggeringLink.href, '_popup', name);
 }
 
 function dismissAddAnotherPopup(win, newId, newRepr) {
     // newId and newRepr are expected to have previously been escaped by
     // django.utils.html.escape.
     newId = html_unescape(newId);
+    var newRepr_escaped = newRepr;
     newRepr = html_unescape(newRepr);
     var name = windowname_to_id(win.name);
     var elem = document.getElementById(name);
@@ -84,6 +110,14 @@
             } else {
                 elem.value = newId;
             }
+            var nameElem = document.getElementById("view_lookup_" + name);
+            if (nameElem) {
+                var chosenIdHref = win.location.href.replace(/\/add\/[^\/]*$/,
+                    '/' + newId + '/');
+                nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' +
+                  'onclick="return showRelatedObjectPopup(this);">' +
+                  newRepr_escaped + '</a> ' + CLEAR_RAW_ID;
+            }
         }
     } else {
         var toId = name + "_to";
@@ -94,3 +128,21 @@
     }
     win.close();
 }
+
+function clearRawId(triggeringLink) {
+    triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = '';
+    triggeringLink.parentNode.innerHTML = '';
+    return false;
+}
+
+function openPopupWindow(href, popup_var, name) {
+    if (href.indexOf('?') == -1) {
+        href += '?';
+    } else {
+        href  += '&';
+    }
+    href += popup_var + '=1';
+    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
+    win.focus();
+    return false;
+}
Index: django/contrib/admin/templatetags/admin_list.py
===================================================================
--- django/contrib/admin/templatetags/admin_list.py	(revision 16669)
+++ django/contrib/admin/templatetags/admin_list.py	(working copy)
@@ -3,8 +3,10 @@
 from django.contrib.admin.util import lookup_field, display_for_field, label_for_field
 from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE,
     ORDER_VAR, PAGE_VAR, SEARCH_VAR)
+from django.contrib.admin.util import obj_label
 from django.contrib.admin.templatetags.admin_static import static
 from django.core.exceptions import ObjectDoesNotExist
+from django.core.urlresolvers import reverse
 from django.db import models
 from django.utils import formats
 from django.utils.html import escape, conditional_escape
@@ -214,8 +216,12 @@
                 attr = pk
             value = result.serializable_value(attr)
             result_id = repr(force_unicode(value))[1:]
-            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \
-                (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
+            result_name = obj_label(result)
+            result_url = reverse('admin:%s_%s_change' % (result._meta.app_label, result._meta.object_name.lower()),
+                                 args=(result.pk,),
+                                 current_app=cl.model_admin.admin_site.name)
+            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' %
+                (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(' "window, %s, '%s', '%s'); return false;\"" % (result_id, result_url, result_name.replace("&#39;", r"\'")) or ''), conditional_escape(result_repr), table_tag))
         else:
             # By default the fields come from ModelAdmin.list_editable, but if we pull
             # the fields out of the form instead of list_editable custom admins
Index: django/contrib/admin/widgets.py
===================================================================
--- django/contrib/admin/widgets.py	(revision 16669)
+++ django/contrib/admin/widgets.py	(working copy)
@@ -13,6 +13,7 @@
 from django.utils.translation import ugettext as _
 from django.utils.safestring import mark_safe
 from django.utils.encoding import force_unicode
+from django.contrib.admin.util import obj_label
 
 
 class FilteredSelectMultiple(forms.SelectMultiple):
@@ -149,13 +150,12 @@
                 attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript code looks for this hook.
             # TODO: "lookup_id_" is hard-coded here. This should instead use
             # the correct API to determine the ID dynamically.
-            extra.append(u'<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> '
+            extra.append(u' <a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> '
                             % (related_url, url, name))
             extra.append(u'<img src="%s" width="16" height="16" alt="%s" /></a>'
                             % (static('admin/img/selector-search.gif'), _('Lookup')))
         output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra
-        if value:
-            output.append(self.label_for_value(value))
+        output.append(self.label_for_value(value, 'view_lookup_id_%s' % name))
         return mark_safe(u''.join(output))
 
     def base_url_parameters(self):
@@ -167,14 +167,38 @@
         params.update({TO_FIELD_VAR: self.rel.get_related_field().name})
         return params
 
-    def label_for_value(self, value):
-        key = self.rel.get_related_field().name
-        try:
-            obj = self.rel.to._default_manager.using(self.db).get(**{key: value})
-            return '&nbsp;<strong>%s</strong>' % escape(Truncator(obj).words(14, truncate='...'))
-        except (ValueError, self.rel.to.DoesNotExist):
-            return ''
+    def label_for_value(self, value, name):
+        if value:
+            key = self.rel.get_related_field().name
+            try:
+                obj = self.rel.to._default_manager.using(
+                        self.db).get(**{key: value})
+            except:
+                label, related_url = '', ''
+            else:
+                label = obj_label(obj)
+                related_url = reverse('admin:%s_%s_change' %
+                                        (obj._meta.app_label,
+                                        obj._meta.module_name),
+                                        args=(obj.pk,),
+                                        current_app=self.admin_site.name)
 
+            return (' <strong id="%(name)s"><a href="%(url)s" '
+                    'onclick="return showRelatedObjectPopup(this);">%(label)s</a> '
+                    '<a href="#" onclick="return clearRawId(this);">'
+                    '<img src="%(img_src)s" '
+                    'width="10" height="10" alt="%(clear)s" title="%(clear)s" />'
+                    '</a></strong>' % {'name': name, 'url': related_url,
+                        'label': label,
+                        'img_src': static('admin/img/icon_deletelink.gif'),
+                        'clear': _("Clear"),}
+                    )
+        else:
+            # a placeholder that will be filled in
+            # JavaScript dismissRelatedLookupPopup()
+            return ' <strong id="%s"></strong>' % name
+
+
 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
     """
     A Widget for displaying ManyToMany ids in the "raw_id" interface rather than
@@ -195,7 +219,7 @@
     def url_parameters(self):
         return self.base_url_parameters()
 
-    def label_for_value(self, value):
+    def label_for_value(self, value, name):
         return ''
 
     def value_from_datadict(self, data, files, name):
Index: django/contrib/admin/util.py
===================================================================
--- django/contrib/admin/util.py	(revision 16669)
+++ django/contrib/admin/util.py	(working copy)
@@ -6,7 +6,7 @@
 from django.utils import formats
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
-from django.utils.text import capfirst
+from django.utils.text import capfirst, truncate_words
 from django.utils.encoding import force_unicode, smart_unicode, smart_str
 from django.utils.translation import ungettext
 from django.core.urlresolvers import reverse
@@ -302,7 +302,10 @@
     else:
         return smart_unicode(value)
 
+def obj_label(obj):
+    return escape(truncate_words(obj, 7))
 
+
 class NotRelationField(Exception):
     pass
 
