Code

Ticket #7028: patch7028-1.4.5.patch

File patch7028-1.4.5.patch, 23.3 KB (added by Stan@…, 16 months ago)

Fix a bug in M2M label when empty.

  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index 78a08cd..2c9df28 100644
    a b from django.forms.models import (modelform_factory, modelformset_factory, 
    66    inlineformset_factory, BaseInlineFormSet) 
    77from django.contrib.contenttypes.models import ContentType 
    88from django.contrib.admin import widgets, helpers 
    9 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 
     9from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict, obj_label 
    1010from django.contrib.admin.templatetags.admin_static import static 
    1111from django.contrib import messages 
    1212from django.views.decorators.csrf import csrf_protect 
    class ModelAdmin(BaseModelAdmin): 
    826826                return HttpResponseRedirect(request.path + "?_popup=1") 
    827827            else: 
    828828                return HttpResponseRedirect(request.path) 
     829        elif "_popup" in request.POST: 
     830            # object changed via raw id link popup 
     831            obj_id = repr(force_unicode(obj._get_pk_val()))[1:] 
     832            obj_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.object_name.lower()), args=(obj.pk,), current_app=self.admin_site.name) 
     833            label = obj_label(obj).replace("'", r"\'") 
     834            return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup(' 
     835            "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label)) 
    829836        elif "_saveasnew" in request.POST: 
    830837            msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} 
    831838            self.message_user(request, msg) 
  • django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js

    diff --git a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
    index ce54fa5..77ea7ee 100644
    a b function html_unescape(text) { 
    1111    return text; 
    1212} 
    1313 
     14function html_escape(text) { 
     15    text = text.replace(/&/g, '&amp;'); 
     16    text = text.replace(/</g, '&lt;'); 
     17    text = text.replace(/>/g, '&gt;'); 
     18    text = text.replace(/"/g, '&quot;'); 
     19    text = text.replace(/'/g, '&#39;'); 
     20    return text; 
     21} 
     22 
    1423// IE doesn't accept periods or dashes in the window name, but the element IDs 
    1524// we use to generate popup window names may contain them, therefore we map them 
    1625// to allowed characters in a reversible way so that we can locate the correct  
    function windowname_to_id(text) { 
    2736    return text; 
    2837} 
    2938 
     39function getAdminMediaPrefix() { 
     40    // Copy-paste from DateTimeShortcuts.js. 
     41        if (window.__admin_media_prefix__ != undefined) { 
     42        return window.__admin_media_prefix__; 
     43    } else { 
     44        return '/missing-admin-media-prefix/'; 
     45    } 
     46} 
     47 
     48var CLEAR_RAW_ID = '<a href="#" onclick="return clearRawId(this);">' + 
     49'<img src="' + getAdminMediaPrefix() + 'img/icon_deletelink.gif" ' + 
     50'width="10" height="10" alt="Clear" title="Clear" /></a>'; 
     51 
     52// FIXME: the following produce 'gettext is not defined' errors in FireBug. 
     53// Needs to be tracked down. 
     54// (jsi18n is generally included before this in admin templates) 
     55// 
     56// 'width="10" height="10" alt="' + gettext('Clear') + '" title="' + 
     57// gettext('Clear') + '" /></a>'; 
     58 
     59function showRelatedObjectPopup(triggeringLink) { 
     60    var name = triggeringLink.parentNode.id.replace(/^view_lookup_/, ''); 
     61    name = id_to_windowname(name); 
     62    return openPopupWindow(triggeringLink.href, '_popup', name); 
     63} 
     64 
    3065function showRelatedObjectLookupPopup(triggeringLink) { 
    3166    var name = triggeringLink.id.replace(/^lookup_/, ''); 
    3267    name = id_to_windowname(name); 
    33     var href; 
    34     if (triggeringLink.href.search(/\?/) >= 0) { 
    35         href = triggeringLink.href + '&pop=1'; 
    36     } else { 
    37         href = triggeringLink.href + '?pop=1'; 
    38     } 
    39     var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); 
    40     win.focus(); 
    41     return false; 
     68    return openPopupWindow(triggeringLink.href, 'pop', name); 
    4269} 
    4370 
    44 function dismissRelatedLookupPopup(win, chosenId) { 
     71function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) { 
    4572    var name = windowname_to_id(win.name); 
    4673    var elem = document.getElementById(name); 
     74    var nameElem = document.getElementById("view_lookup_" + name); 
    4775    if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { 
    4876        elem.value += ',' + chosenId; 
    4977    } else { 
    5078        document.getElementById(name).value = chosenId; 
    5179    } 
     80    if (nameElem) { 
     81      nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 
     82       'onclick="return showRelatedObjectPopup(this);">' + 
     83        html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID; 
     84    } 
    5285    win.close(); 
    5386} 
    5487 
    5588function showAddAnotherPopup(triggeringLink) { 
    5689    var name = triggeringLink.id.replace(/^add_/, ''); 
    5790    name = id_to_windowname(name); 
    58     href = triggeringLink.href 
    59     if (href.indexOf('?') == -1) { 
    60         href += '?_popup=1'; 
    61     } else { 
    62         href  += '&_popup=1'; 
    63     } 
    64     var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); 
    65     win.focus(); 
    66     return false; 
     91    return openPopupWindow(triggeringLink.href, '_popup', name); 
    6792} 
    6893 
    6994function dismissAddAnotherPopup(win, newId, newRepr) { 
    7095    // newId and newRepr are expected to have previously been escaped by 
    7196    // django.utils.html.escape. 
    7297    newId = html_unescape(newId); 
     98    var newRepr_escaped = newRepr; 
    7399    newRepr = html_unescape(newRepr); 
    74100    var name = windowname_to_id(win.name); 
    75101    var elem = document.getElementById(name); 
    function dismissAddAnotherPopup(win, newId, newRepr) { 
    85111            } else { 
    86112                elem.value = newId; 
    87113            } 
     114            var nameElem = document.getElementById("view_lookup_" + name); 
     115            if (nameElem) { 
     116                var chosenIdHref = win.location.href.replace(/\/add\/[^\/]*$/, 
     117                    '/' + newId + '/'); 
     118                nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 
     119                  'onclick="return showRelatedObjectPopup(this);">' + 
     120                  newRepr_escaped + '</a> ' + CLEAR_RAW_ID; 
     121            } 
    88122        } 
    89123    } else { 
    90124        var toId = name + "_to"; 
    function dismissAddAnotherPopup(win, newId, newRepr) { 
    95129    } 
    96130    win.close(); 
    97131} 
     132 
     133function clearRawId(triggeringLink) { 
     134    triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = ''; 
     135    triggeringLink.parentNode.innerHTML = ''; 
     136    return false; 
     137} 
     138 
     139function openPopupWindow(href, popup_var, name) { 
     140    if (href.indexOf('?') == -1) { 
     141        href += '?'; 
     142    } else { 
     143        href  += '&'; 
     144    } 
     145    href += popup_var + '=1'; 
     146    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); 
     147    win.focus(); 
     148    return false; 
     149} 
  • django/contrib/admin/templatetags/admin_list.py

    diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
    index e778429..036c0e0 100644
    a b import datetime 
    33from django.contrib.admin.util import lookup_field, display_for_field, label_for_field 
    44from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 
    55    ORDER_VAR, PAGE_VAR, SEARCH_VAR) 
     6from django.contrib.admin.util import obj_label 
    67from django.contrib.admin.templatetags.admin_static import static 
    78from django.core.exceptions import ObjectDoesNotExist 
     9from django.core.urlresolvers import reverse 
    810from django.db import models 
    911from django.utils import formats 
    1012from django.utils.html import escape, conditional_escape 
    def items_for_result(cl, result, form): 
    221223                attr = pk 
    222224            value = result.serializable_value(attr) 
    223225            result_id = repr(force_unicode(value))[1:] 
    224             yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 
    225                 (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)) 
     226            result_name = obj_label(result) 
     227            result_url = reverse('admin:%s_%s_change' % (result._meta.app_label, result._meta.object_name.lower()), 
     228                                 args=(result.pk,), 
     229                                 current_app=cl.model_admin.admin_site.name) 
     230            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % 
     231                (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)) 
    226232        else: 
    227233            # By default the fields come from ModelAdmin.list_editable, but if we pull 
    228234            # the fields out of the form instead of list_editable custom admins 
  • django/contrib/admin/util.py

    diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py
    index 61182a6..16b276c 100644
    a b from django.forms.forms import pretty_name 
    66from django.utils import formats 
    77from django.utils.html import escape 
    88from django.utils.safestring import mark_safe 
    9 from django.utils.text import capfirst 
     9from django.utils.text import capfirst, truncate_words 
    1010from django.utils import timezone 
    1111from django.utils.encoding import force_unicode, smart_unicode, smart_str 
    1212from django.utils.translation import ungettext 
    def display_for_field(value, field): 
    332332    else: 
    333333        return smart_unicode(value) 
    334334 
     335def obj_label(obj): 
     336    return escape(truncate_words(obj, 7)) 
     337 
    335338 
    336339class NotRelationField(Exception): 
    337340    pass 
  • django/contrib/admin/widgets.py

    diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
    index 29958b2..0064ebb 100644
    a b from django.core.urlresolvers import reverse 
    99from django.forms.widgets import RadioFieldRenderer 
    1010from django.forms.util import flatatt 
    1111from django.utils.html import escape 
    12 from django.utils.text import Truncator 
     12from django.utils.text import Truncator, truncate_words 
    1313from django.utils.translation import ugettext as _ 
    1414from django.utils.safestring import mark_safe 
    1515from django.utils.encoding import force_unicode 
     16from django.contrib.admin.util import obj_label 
    1617 
    1718 
    1819class FilteredSelectMultiple(forms.SelectMultiple): 
    class ForeignKeyRawIdWidget(forms.TextInput): 
    160161            extra.append(u'<img src="%s" width="16" height="16" alt="%s" /></a>' 
    161162                            % (static('admin/img/selector-search.gif'), _('Lookup'))) 
    162163        output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra 
    163         if value: 
    164             output.append(self.label_for_value(value)) 
     164        output.append(self.label_for_value(value, 'view_lookup_id_%s' % name)) 
    165165        return mark_safe(u''.join(output)) 
    166166 
    167167    def base_url_parameters(self): 
    class ForeignKeyRawIdWidget(forms.TextInput): 
    173173        params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 
    174174        return params 
    175175 
    176     def label_for_value(self, value): 
    177         key = self.rel.get_related_field().name 
    178         try: 
    179             obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) 
    180             return '&nbsp;<strong>%s</strong>' % escape(Truncator(obj).words(14, truncate='...')) 
    181         except (ValueError, self.rel.to.DoesNotExist): 
    182             return '' 
     176    def label_for_value(self, value, name): 
     177        if value: 
     178            rel_to = self.rel.to 
     179            label, related_url = '', '' 
     180            key = self.rel.get_related_field().name 
     181            try: 
     182                obj = rel_to._default_manager.using( 
     183                        self.db).get(**{key: value}) 
     184            except: 
     185                pass 
     186            else: 
     187                label = obj_label(obj) 
     188                if rel_to in self.admin_site._registry: 
     189                    try: 
     190                        related_url = reverse('admin:%s_%s_change' % 
     191                                                (obj._meta.app_label, 
     192                                                obj._meta.module_name), 
     193                                                args=(obj.pk,), 
     194                                                current_app=self.admin_site.name) 
     195                    except NoReverseMatch: 
     196                        raise 
     197            if label and related_url: 
     198                label = '<a href="%s" onclick="return showRelatedObjectPopup(this);">%s</a>' % (related_url, label) 
     199 
     200            return ('&nbsp;<strong id="%(name)s">%(label)s' 
     201                    '&nbsp;<a href="#" onclick="return clearRawId(this);">' 
     202                    '<img src="%(img_src)s" ' 
     203                    'width="10" height="10" alt="%(clear)s" title="%(clear)s" />' 
     204                    '</a></strong>' % {'name': name,  
     205                                       'label': label, 
     206                                       'img_src': static('admin/img/icon_deletelink.gif'), 
     207                                       'clear': _("Clear")} 
     208                   ) 
     209        else: 
     210            # a placeholder that will be filled in 
     211            # JavaScript dismissRelatedLookupPopup() 
     212            return ' <strong id="%s"></strong>' % name 
     213 
    183214 
    184215class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 
    185216    """ 
    class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 
    201232    def url_parameters(self): 
    202233        return self.base_url_parameters() 
    203234 
    204     def label_for_value(self, value): 
    205         return '' 
     235    def label_for_value(self, value, name): 
     236        if not value: 
     237            return '' 
     238        value = [int(v) for v in value.split(',')] 
     239        objs = self.rel.to._default_manager.filter(pk__in=value) 
     240        return '&nbsp;<strong>%s</strong>' % ',&nbsp;'.join(truncate_words(obj, 14) for obj in objs) 
    206241 
    207242    def value_from_datadict(self, data, files, name): 
    208243        value = data.get(name) 
  • tests/regressiontests/admin_widgets/tests.py

    diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py
    index 87e0309..786970b 100644
    a b class ForeignKeyRawIdWidgetTest(DjangoTestCase): 
    292292        w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 
    293293        self.assertHTMLEqual( 
    294294            conditional_escape(w.render('test', band.pk, attrs={})), 
    295             '<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Linkin Park</strong>' % dict(admin_media_prefix(), bandpk=band.pk) 
     295            '<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/band/1/" onclick="return showRelatedObjectPopup(this);">Linkin Park</a>&nbsp;<a href="#" onclick="return clearRawId(this);"><img src="%(ADMIN_MEDIA_PREFIX)simg/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % dict(admin_media_prefix(), bandpk=band.pk) 
    296296        ) 
    297297 
    298298    def test_relations_to_non_primary_key(self): 
    class ForeignKeyRawIdWidgetTest(DjangoTestCase): 
    307307        w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 
    308308        self.assertHTMLEqual( 
    309309            w.render('test', core.parent_id, attrs={}), 
    310             '<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Apple</strong>' % admin_media_prefix() 
     310            u'<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/inventory/1/" onclick="return showRelatedObjectPopup(this);">Apple</a>&nbsp;<a href="#" onclick="return clearRawId(this);"><img src="%(ADMIN_MEDIA_PREFIX)simg/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % admin_media_prefix() 
    311311        ) 
    312312 
    313313    def test_fk_related_model_not_in_admin(self): 
    class ForeignKeyRawIdWidgetTest(DjangoTestCase): 
    320320        w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 
    321321        self.assertHTMLEqual( 
    322322            conditional_escape(w.render('honeycomb_widget', big_honeycomb.pk, attrs={})), 
    323             '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" />&nbsp;<strong>Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk} 
     323            '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" />&nbsp;<strong id="view_lookup_id_honeycomb_widget">Honeycomb object&nbsp;<a href="#" onclick="return clearRawId(this);"><img src="/static/admin/img/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % {'hcombpk': big_honeycomb.pk} 
    324324        ) 
    325325 
    326326    def test_fk_to_self_model_not_in_admin(self): 
    class ForeignKeyRawIdWidgetTest(DjangoTestCase): 
    333333        w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 
    334334        self.assertHTMLEqual( 
    335335            conditional_escape(w.render('individual_widget', subject1.pk, attrs={})), 
    336             '<input type="text" name="individual_widget" value="%(subj1pk)s" />&nbsp;<strong>Individual object</strong>' % {'subj1pk': subject1.pk} 
     336            '<input type="text" name="individual_widget" value="%(subj1pk)s" />&nbsp;<strong id="view_lookup_id_individual_widget">Individual object&nbsp;<a href="#" onclick="return clearRawId(this);"><img src="/static/admin/img/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % {'subj1pk': subject1.pk} 
    337337        ) 
    338338 
    339339    def test_proper_manager_for_label_lookup(self): 
    class ForeignKeyRawIdWidgetTest(DjangoTestCase): 
    349349        ) 
    350350        self.assertHTMLEqual( 
    351351            w.render('test', child_of_hidden.parent_id, attrs={}), 
    352             '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Hidden</strong>' % admin_media_prefix() 
     352            '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/inventory/1/" onclick="return showRelatedObjectPopup(this);">Hidden</a>&nbsp;<a href="#" onclick="return clearRawId(this);"><img src="%(ADMIN_MEDIA_PREFIX)simg/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % admin_media_prefix() 
    353353        ) 
    354354 
    355355 
    class ManyToManyRawIdWidgetTest(DjangoTestCase): 
    365365        w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) 
    366366        self.assertHTMLEqual( 
    367367            conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})), 
    368             '<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="/static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk) 
     368            '<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Chester,&nbsp;Mike</strong>' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk) 
    369369        ) 
    370370 
    371371        self.assertHTMLEqual( 
    372372            conditional_escape(w.render('test', [m1.pk])), 
    373             '<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_media_prefix(), m1pk=m1.pk) 
     373            '<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a>&nbsp;<strong>Chester</strong>' % dict(admin_media_prefix(), m1pk=m1.pk) 
    374374        ) 
    375375 
    376376        self.assertEqual(w._has_changed(None, None), False) 
    class ManyToManyRawIdWidgetTest(DjangoTestCase): 
    393393        w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) 
    394394        self.assertHTMLEqual( 
    395395            conditional_escape(w.render('company_widget1', [c1.pk, c2.pk], attrs={})), 
    396             '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" />' % {'c1pk': c1.pk, 'c2pk': c2.pk} 
     396            '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" />&nbsp;<strong>Company object,&nbsp;Company object</strong>' % {'c1pk': c1.pk, 'c2pk': c2.pk} 
    397397        ) 
    398398 
    399399        self.assertHTMLEqual( 
    400400            conditional_escape(w.render('company_widget2', [c1.pk])), 
    401             '<input type="text" name="company_widget2" value="%(c1pk)s" />' % {'c1pk': c1.pk} 
     401            '<input type="text" name="company_widget2" value="%(c1pk)s" />&nbsp;<strong>Company object</strong>' % {'c1pk': c1.pk} 
    402402        ) 
    403403 
    404404class RelatedFieldWidgetWrapperTests(DjangoTestCase): 
    class HorizontalVerticalFilterSeleniumChromeTests(HorizontalVerticalFilterSeleni 
    691691    webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver' 
    692692 
    693693class HorizontalVerticalFilterSeleniumIETests(HorizontalVerticalFilterSeleniumFirefoxTests): 
    694     webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver' 
    695  No newline at end of file 
     694    webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'