Ticket #7028: patch7028-1.4.rev16961.2.patch
File patch7028-1.4.rev16961.2.patch, 22.1 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/options.py
5 5 inlineformset_factory, BaseInlineFormSet) 6 6 from django.contrib.contenttypes.models import ContentType 7 7 from django.contrib.admin import widgets, helpers 8 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 8 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict, obj_label 9 9 from django.contrib.admin.templatetags.admin_static import static 10 10 from django.contrib import messages 11 11 from django.views.decorators.csrf import csrf_protect … … 819 819 return HttpResponseRedirect(request.path + "?_popup=1") 820 820 else: 821 821 return HttpResponseRedirect(request.path) 822 elif "_popup" in request.POST: 823 # object changed via raw id link popup 824 obj_id = repr(force_unicode(obj._get_pk_val()))[1:] 825 obj_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.object_name.lower()), args=(obj.pk,), current_app=self.admin_site.name) 826 label = obj_label(obj).replace("'", r"\'") 827 return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup(' 828 "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label)) 822 829 elif "_saveasnew" in request.POST: 823 830 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} 824 831 self.message_user(request, msg) -
django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
11 11 return text; 12 12 } 13 13 14 function html_escape(text) { 15 text = text.replace(/&/g, '&'); 16 text = text.replace(/</g, '<'); 17 text = text.replace(/>/g, '>'); 18 text = text.replace(/"/g, '"'); 19 text = text.replace(/'/g, '''); 20 return text; 21 } 22 14 23 // IE doesn't accept periods or dashes in the window name, but the element IDs 15 24 // we use to generate popup window names may contain them, therefore we map them 16 25 // to allowed characters in a reversible way so that we can locate the correct … … 27 36 return text; 28 37 } 29 38 39 function 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 48 var 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 59 function 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 30 65 function showRelatedObjectLookupPopup(triggeringLink) { 31 66 var name = triggeringLink.id.replace(/^lookup_/, ''); 32 67 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); 42 69 } 43 70 44 function dismissRelatedLookupPopup(win, chosenId ) {71 function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) { 45 72 var name = windowname_to_id(win.name); 46 73 var elem = document.getElementById(name); 74 var nameElem = document.getElementById("view_lookup_" + name); 47 75 if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { 48 76 elem.value += ',' + chosenId; 49 77 } else { 50 78 document.getElementById(name).value = chosenId; 51 79 } 80 if (nameElem) { 81 nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 82 'onclick="return showRelatedObjectPopup(this);">' + 83 html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID; 84 } 52 85 win.close(); 53 86 } 54 87 55 88 function showAddAnotherPopup(triggeringLink) { 56 89 var name = triggeringLink.id.replace(/^add_/, ''); 57 90 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); 67 92 } 68 93 69 94 function dismissAddAnotherPopup(win, newId, newRepr) { 70 95 // newId and newRepr are expected to have previously been escaped by 71 96 // django.utils.html.escape. 72 97 newId = html_unescape(newId); 98 var newRepr_escaped = newRepr; 73 99 newRepr = html_unescape(newRepr); 74 100 var name = windowname_to_id(win.name); 75 101 var elem = document.getElementById(name); … … 84 110 } else { 85 111 elem.value = newId; 86 112 } 113 var nameElem = document.getElementById("view_lookup_" + name); 114 if (nameElem) { 115 var chosenIdHref = win.location.href.replace(/\/add\/[^\/]*$/, 116 '/' + newId + '/'); 117 nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 118 'onclick="return showRelatedObjectPopup(this);">' + 119 newRepr_escaped + '</a> ' + CLEAR_RAW_ID; 120 } 87 121 } 88 122 } else { 89 123 var toId = name + "_to"; … … 94 128 } 95 129 win.close(); 96 130 } 131 132 function clearRawId(triggeringLink) { 133 triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = ''; 134 triggeringLink.parentNode.innerHTML = ''; 135 return false; 136 } 137 138 function openPopupWindow(href, popup_var, name) { 139 if (href.indexOf('?') == -1) { 140 href += '?'; 141 } else { 142 href += '&'; 143 } 144 href += popup_var + '=1'; 145 var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); 146 win.focus(); 147 return false; 148 } -
django/contrib/admin/templatetags/admin_list.py
3 3 from django.contrib.admin.util import lookup_field, display_for_field, label_for_field 4 4 from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 5 5 ORDER_VAR, PAGE_VAR, SEARCH_VAR) 6 from django.contrib.admin.util import obj_label 6 7 from django.contrib.admin.templatetags.admin_static import static 7 8 from django.core.exceptions import ObjectDoesNotExist 9 from django.core.urlresolvers import reverse 8 10 from django.db import models 9 11 from django.utils import formats 10 12 from django.utils.html import escape, conditional_escape … … 220 222 attr = pk 221 223 value = result.serializable_value(attr) 222 224 result_id = repr(force_unicode(value))[1:] 223 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 224 (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)) 225 result_name = obj_label(result) 226 result_url = reverse('admin:%s_%s_change' % (result._meta.app_label, result._meta.object_name.lower()), 227 args=(result.pk,), 228 current_app=cl.model_admin.admin_site.name) 229 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % 230 (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("'", r"\'")) or ''), conditional_escape(result_repr), table_tag)) 225 231 else: 226 232 # By default the fields come from ModelAdmin.list_editable, but if we pull 227 233 # the fields out of the form instead of list_editable custom admins -
django/contrib/admin/widgets.py
9 9 from django.forms.widgets import RadioFieldRenderer 10 10 from django.forms.util import flatatt 11 11 from django.utils.html import escape 12 from django.utils.text import Truncator 12 from django.utils.text import Truncator, truncate_words 13 13 from django.utils.translation import ugettext as _ 14 14 from django.utils.safestring import mark_safe 15 15 from django.utils.encoding import force_unicode 16 from django.contrib.admin.util import obj_label 16 17 17 18 18 19 class FilteredSelectMultiple(forms.SelectMultiple): … … 154 155 extra.append(u'<img src="%s" width="16" height="16" alt="%s" /></a>' 155 156 % (static('admin/img/selector-search.gif'), _('Lookup'))) 156 157 output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra 157 if value: 158 output.append(self.label_for_value(value)) 158 output.append(self.label_for_value(value, 'view_lookup_id_%s' % name)) 159 159 return mark_safe(u''.join(output)) 160 160 161 161 def base_url_parameters(self): … … 167 167 params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 168 168 return params 169 169 170 def label_for_value(self, value): 171 key = self.rel.get_related_field().name 172 try: 173 obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) 174 return ' <strong>%s</strong>' % escape(Truncator(obj).words(14, truncate='...')) 175 except (ValueError, self.rel.to.DoesNotExist): 176 return '' 170 def label_for_value(self, value, name): 171 if value: 172 rel_to = self.rel.to 173 label, related_url = '', '' 174 key = self.rel.get_related_field().name 175 try: 176 obj = rel_to._default_manager.using( 177 self.db).get(**{key: value}) 178 except: 179 pass 180 else: 181 label = obj_label(obj) 182 if rel_to in self.admin_site._registry: 183 try: 184 related_url = reverse('admin:%s_%s_change' % 185 (obj._meta.app_label, 186 obj._meta.module_name), 187 args=(obj.pk,), 188 current_app=self.admin_site.name) 189 except NoReverseMatch: 190 raise 191 if label and related_url: 192 label = '<a href="%s" onclick="return showRelatedObjectPopup(this);">%s</a>' % (related_url, label) 177 193 194 return (' <strong id="%(name)s">%(label)s' 195 ' <a href="#" onclick="return clearRawId(this);">' 196 '<img src="%(img_src)s" ' 197 'width="10" height="10" alt="%(clear)s" title="%(clear)s" />' 198 '</a></strong>' % {'name': name, 199 'label': label, 200 'img_src': static('admin/img/icon_deletelink.gif'), 201 'clear': _("Clear")} 202 ) 203 else: 204 # a placeholder that will be filled in 205 # JavaScript dismissRelatedLookupPopup() 206 return ' <strong id="%s"></strong>' % name 207 208 178 209 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 179 210 """ 180 211 A Widget for displaying ManyToMany ids in the "raw_id" interface rather than … … 195 226 def url_parameters(self): 196 227 return self.base_url_parameters() 197 228 198 def label_for_value(self, value): 199 return '' 229 def label_for_value(self, value, name): 230 value = [int(v) for v in value.split(',')] 231 objs = self.rel.to._default_manager.filter(pk__in=value) 232 return ' <strong>%s</strong>' % ', '.join(truncate_words(obj, 14) for obj in objs) 200 233 201 234 def value_from_datadict(self, data, files, name): 202 235 value = data.get(name) -
django/contrib/admin/util.py
6 6 from django.utils import formats 7 7 from django.utils.html import escape 8 8 from django.utils.safestring import mark_safe 9 from django.utils.text import capfirst 9 from django.utils.text import capfirst, truncate_words 10 10 from django.utils.encoding import force_unicode, smart_unicode, smart_str 11 11 from django.utils.translation import ungettext 12 12 from django.core.urlresolvers import reverse … … 302 302 else: 303 303 return smart_unicode(value) 304 304 305 def obj_label(obj): 306 return escape(truncate_words(obj, 7)) 305 307 308 306 309 class NotRelationField(Exception): 307 310 pass 308 311 -
tests/regressiontests/admin_widgets/tests.py
255 255 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 256 256 self.assertEqual( 257 257 conditional_escape(w.render('test', band.pk, attrs={})), 258 '<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> <strong >Linkin Park</strong>' % dict(admin_media_prefix(), bandpk=band.pk)258 '<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> <strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/band/1/" onclick="return showRelatedObjectPopup(this);">Linkin Park</a> <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) 259 259 ) 260 260 261 261 def test_relations_to_non_primary_key(self): … … 270 270 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 271 271 self.assertEqual( 272 272 w.render('test', core.parent_id, attrs={}), 273 '<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> <strong>Apple</strong>' % admin_media_prefix()273 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> <strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/inventory/1/" onclick="return showRelatedObjectPopup(this);">Apple</a> <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() 274 274 ) 275 275 276 276 def test_fk_related_model_not_in_admin(self): … … 283 283 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 284 284 self.assertEqual( 285 285 conditional_escape(w.render('honeycomb_widget', big_honeycomb.pk, attrs={})), 286 '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" /> <strong >Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk}286 '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" /> <strong id="view_lookup_id_honeycomb_widget">Honeycomb object <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} 287 287 ) 288 288 289 289 def test_fk_to_self_model_not_in_admin(self): … … 296 296 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 297 297 self.assertEqual( 298 298 conditional_escape(w.render('individual_widget', subject1.pk, attrs={})), 299 '<input type="text" name="individual_widget" value="%(subj1pk)s" /> <strong >Individual object</strong>' % {'subj1pk': subject1.pk}299 '<input type="text" name="individual_widget" value="%(subj1pk)s" /> <strong id="view_lookup_id_individual_widget">Individual object <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} 300 300 ) 301 301 302 302 def test_proper_manager_for_label_lookup(self): … … 312 312 ) 313 313 self.assertEqual( 314 314 w.render('test', child_of_hidden.parent_id, attrs={}), 315 '<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> <strong >Hidden</strong>' % admin_media_prefix()315 '<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> <strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/inventory/1/" onclick="return showRelatedObjectPopup(this);">Hidden</a> <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() 316 316 ) 317 317 318 318 … … 328 328 w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) 329 329 self.assertEqual( 330 330 conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})), 331 '<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)331 '<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> <strong>Chester, Mike</strong>' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk) 332 332 ) 333 333 334 334 self.assertEqual( 335 335 conditional_escape(w.render('test', [m1.pk])), 336 '<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)336 '<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> <strong>Chester</strong>' % dict(admin_media_prefix(), m1pk=m1.pk) 337 337 ) 338 338 339 339 self.assertEqual(w._has_changed(None, None), False) … … 356 356 w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) 357 357 self.assertEqual( 358 358 conditional_escape(w.render('company_widget1', [c1.pk, c2.pk], attrs={})), 359 '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" /> ' % {'c1pk': c1.pk, 'c2pk': c2.pk}359 '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" /> <strong>Company object, Company object</strong>' % {'c1pk': c1.pk, 'c2pk': c2.pk} 360 360 ) 361 361 362 362 self.assertEqual( 363 363 conditional_escape(w.render('company_widget2', [c1.pk])), 364 '<input type="text" name="company_widget2" value="%(c1pk)s" /> ' % {'c1pk': c1.pk}364 '<input type="text" name="company_widget2" value="%(c1pk)s" /> <strong>Company object</strong>' % {'c1pk': c1.pk} 365 365 ) 366 366 367 367 class RelatedFieldWidgetWrapperTests(DjangoTestCase):