Ticket #1375: string_pkey_in_admin.patch

File string_pkey_in_admin.patch, 7.2 KB (added by yk4ever, 8 years ago)

Improved patch

  • django/contrib/admin/models.py

     
    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

     
    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

     
    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)
Back to Top