Django

Code

Ticket #1375: string_pkey_in_admin.patch

File string_pkey_in_admin.patch, 7.2 kB (added by yk4ever, 7 months ago)

Improved patch

  • django/contrib/admin/models.py

    old new  
    44from django.utils.translation import ugettext_lazy as _ 
    55from django.utils.encoding import smart_unicode 
    66from django.utils.safestring import mark_safe 
     7from urllib import quote, unquote 
    78 
    89ADDITION = 1 
    910CHANGE = 2 
    1011DELETION = 3 
    1112 
     13def 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 
     29def 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 
    1249class LogEntryManager(models.Manager): 
    1350    def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''): 
    1451        e = self.model(None, None, user_id, content_type_id, smart_unicode(object_id), object_repr[:200], action_flag, change_message) 
     
    5087        Returns the admin URL to edit the object represented by this log entry. 
    5188        This is relative to the Django admin index page. 
    5289        """ 
    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

    old new  
    1111from django.utils.encoding import smart_unicode, smart_str, force_unicode 
    1212from django.template import Library 
    1313import datetime 
     14from urllib import quote 
    1415 
    1516register = Library() 
    1617 
     
    197198            # Problem cases are long ints (23L) and non-ASCII strings. 
    198199            result_id = repr(force_unicode(getattr(result, pk)))[1:] 
    199200            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)) 
    201202        else: 
    202203            yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr))) 
    203204 
  • django/contrib/admin/views/main.py

    old new  
    2222except NameError: 
    2323    from sets import Set as set   # Python 2.3 fallback 
    2424 
    25 from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION 
     25from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION, pk_url_quote, pk_url_unquote 
    2626if not LogEntry._meta.installed: 
    2727    raise ImproperlyConfigured, "You'll need to put 'django.contrib.admin' in your INSTALLED_APPS setting before you can use the admin application." 
    2828 
     
    5050class IncorrectLookupParameters(Exception): 
    5151    pass 
    5252 
    53 def quote(s): 
    54     """ 
    55     Ensure that primary key values do not confuse the admin URLs by escaping 
    56     any '/', '_' and ':' characters. Similar to urllib.quote, except that the 
    57     quoting is slightly different so that it doesn't get automatically 
    58     unquoted by the Web browser. 
    59     """ 
    60     if type(s) != type(''): 
    61         return s 
    62     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 = chr 
    74     myatoi = int 
    75     list = s.split('_') 
    76     res = [list[0]] 
    77     myappend = res.append 
    78     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  
    8953def get_javascript_imports(opts, auto_populated_fields, field_sets): 
    9054# Put in any necessary JavaScript imports. 
    9155    js = ['js/core.js', 'js/admin/RelatedObjectLookups.js'] 
     
    309273 
    310274def change_stage(request, app_label, model_name, object_id): 
    311275    model = models.get_model(app_label, model_name) 
    312     object_id = unquote(object_id) 
     276    object_id = pk_url_unquote(object_id) 
    313277    if model is None: 
    314278        raise Http404("App %r, model %r, not found" % (app_label, model_name)) 
    315279    opts = model._meta 
     
    501465 
    502466def delete_stage(request, app_label, model_name, object_id): 
    503467    model = models.get_model(app_label, model_name) 
    504     object_id = unquote(object_id) 
     468    object_id = pk_url_unquote(object_id) 
    505469    if model is None: 
    506470        raise Http404("App %r, model %r, not found" % (app_label, model_name)) 
    507471    opts = model._meta 
     
    511475 
    512476    # Populate deleted_objects, a data structure of all related objects that 
    513477    # 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))), []] 
    515479    perms_needed = set() 
    516480    _get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1) 
    517481 
     
    538502 
    539503def history(request, app_label, model_name, object_id): 
    540504    model = models.get_model(app_label, model_name) 
    541     object_id = unquote(object_id) 
     505    object_id = pk_url_unquote(object_id) 
    542506    if model is None: 
    543507        raise Http404("App %r, model %r, not found" % (app_label, model_name)) 
    544508    action_list = LogEntry.objects.filter(object_id=object_id, 
     
    764728        return qs 
    765729 
    766730    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)) 
    768732 
    769733def change_list(request, app_label, model_name): 
    770734    model = models.get_model(app_label, model_name)