Ticket #1375: string_pkey_in_admin.patch
File string_pkey_in_admin.patch, 7.2 KB (added by , 17 years ago) |
---|
-
django/contrib/admin/models.py
4 4 from django.utils.translation import ugettext_lazy as _ 5 5 from django.utils.encoding import smart_unicode 6 6 from django.utils.safestring import mark_safe 7 from urllib import quote, unquote 7 8 8 9 ADDITION = 1 9 10 CHANGE = 2 10 11 DELETION = 3 11 12 13 def pk_url_quote(s): 14 """ 15 Ensure that primary key values do not confuse the admin URLs by escaping 16 any special URL characters. Similar to urllib.quote, except that the 17 quoting is slightly different so that it doesn't get automatically 18 unquoted by the Web browser. 19 """ 20 if type(s) != str and type(s) != unicode: 21 return s 22 res = list(s) 23 for i in range(len(res)): 24 c = res[i] 25 if c in ':/.#?@=&;': 26 res[i] = '.%02X' % ord(c) 27 return ''.join(res) 28 29 def pk_url_unquote(s): 30 """ 31 Undo the effects of pk_url_quote(). Based heavily on urllib.unquote(). 32 """ 33 mychr = chr 34 myatoi = int 35 list = s.split('.') 36 res = [list[0]] 37 myappend = res.append 38 del list[0] 39 for item in list: 40 if item[1:2]: 41 try: 42 myappend(mychr(myatoi(item[:2], 16)) + item[2:]) 43 except ValueError: 44 myappend('.' + item) 45 else: 46 myappend('.' + item) 47 return "".join(res) 48 12 49 class LogEntryManager(models.Manager): 13 50 def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''): 14 51 e = self.model(None, None, user_id, content_type_id, smart_unicode(object_id), object_repr[:200], action_flag, change_message) … … 50 87 Returns the admin URL to edit the object represented by this log entry. 51 88 This is relative to the Django admin index page. 52 89 """ 53 return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id))90 return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, quote(pk_url_quote(self.object_id)))) -
django/contrib/admin/templatetags/admin_list.py
11 11 from django.utils.encoding import smart_unicode, smart_str, force_unicode 12 12 from django.template import Library 13 13 import datetime 14 from urllib import quote 14 15 15 16 register = Library() 16 17 … … 197 198 # Problem cases are long ints (23L) and non-ASCII strings. 198 199 result_id = repr(force_unicode(getattr(result, pk)))[1:] 199 200 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 200 (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))201 (table_tag, row_class, quote(url), (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag)) 201 202 else: 202 203 yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr))) 203 204 -
django/contrib/admin/views/main.py
22 22 except NameError: 23 23 from sets import Set as set # Python 2.3 fallback 24 24 25 from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION 25 from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION, pk_url_quote, pk_url_unquote 26 26 if not LogEntry._meta.installed: 27 27 raise ImproperlyConfigured, "You'll need to put 'django.contrib.admin' in your INSTALLED_APPS setting before you can use the admin application." 28 28 … … 50 50 class IncorrectLookupParameters(Exception): 51 51 pass 52 52 53 def quote(s):54 """55 Ensure that primary key values do not confuse the admin URLs by escaping56 any '/', '_' and ':' characters. Similar to urllib.quote, except that the57 quoting is slightly different so that it doesn't get automatically58 unquoted by the Web browser.59 """60 if type(s) != type(''):61 return s62 res = list(s)63 for i in range(len(res)):64 c = res[i]65 if c in ':/_':66 res[i] = '_%02X' % ord(c)67 return ''.join(res)68 69 def unquote(s):70 """71 Undo the effects of quote(). Based heavily on urllib.unquote().72 """73 mychr = chr74 myatoi = int75 list = s.split('_')76 res = [list[0]]77 myappend = res.append78 del list[0]79 for item in list:80 if item[1:2]:81 try:82 myappend(mychr(myatoi(item[:2], 16)) + item[2:])83 except ValueError:84 myappend('_' + item)85 else:86 myappend('_' + item)87 return "".join(res)88 89 53 def get_javascript_imports(opts, auto_populated_fields, field_sets): 90 54 # Put in any necessary JavaScript imports. 91 55 js = ['js/core.js', 'js/admin/RelatedObjectLookups.js'] … … 309 273 310 274 def change_stage(request, app_label, model_name, object_id): 311 275 model = models.get_model(app_label, model_name) 312 object_id = unquote(object_id)276 object_id = pk_url_unquote(object_id) 313 277 if model is None: 314 278 raise Http404("App %r, model %r, not found" % (app_label, model_name)) 315 279 opts = model._meta … … 501 465 502 466 def delete_stage(request, app_label, model_name, object_id): 503 467 model = models.get_model(app_label, model_name) 504 object_id = unquote(object_id)468 object_id = pk_url_unquote(object_id) 505 469 if model is None: 506 470 raise Http404("App %r, model %r, not found" % (app_label, model_name)) 507 471 opts = model._meta … … 511 475 512 476 # Populate deleted_objects, a data structure of all related objects that 513 477 # will also be deleted. 514 deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), force_unicode(object_id), escape(obj))), []]478 deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), pk_url_quote(force_unicode(object_id)), escape(obj))), []] 515 479 perms_needed = set() 516 480 _get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1) 517 481 … … 538 502 539 503 def history(request, app_label, model_name, object_id): 540 504 model = models.get_model(app_label, model_name) 541 object_id = unquote(object_id)505 object_id = pk_url_unquote(object_id) 542 506 if model is None: 543 507 raise Http404("App %r, model %r, not found" % (app_label, model_name)) 544 508 action_list = LogEntry.objects.filter(object_id=object_id, … … 764 728 return qs 765 729 766 730 def url_for_result(self, result): 767 return "%s/" % quote(getattr(result, self.pk_attname))731 return "%s/" % pk_url_quote(getattr(result, self.pk_attname)) 768 732 769 733 def change_list(request, app_label, model_name): 770 734 model = models.get_model(app_label, model_name)