如何安全地覆盖django.contrib.admin.utils quote()方法?

时间:2018-10-09 20:23:34

标签: python django django-admin

看来quote()中的unquote()django.contrib.admin.utils方法不能有效地处理主键中的下划线。具体来说,我有一些看起来像cus_C2xVQnht的字符串型主键,当我使用django管理界面通过小铅笔图标对其进行编辑时,弹出窗口将显示类似Customer with ID "cusÂxVQnht" doesn't exist. Perhaps it was deleted?的错误(它正在将 C2 转换为代码点 00C2 ,又名 。其他有效代码点(00C7、00C6、001B等)也是如此)

如果我手动转到客户模型并找到ID,则可以将其调好并进行编辑,但是当主键中带有下划线时,URL编码似乎无法正常工作。

经过大量的挖掘,我设法找到了埋在django.contrib.admin.utils内部的这两个函数:

def quote(s):
    """
    Ensure that primary key values do not confuse the admin URLs by escaping
    any '/', '_' and ':' and similarly problematic characters.
    Similar to urllib.parse.quote(), except that the quoting is slightly
    different so that it doesn't get automatically unquoted by the Web browser.
    """
    if not isinstance(s, str):
        return s
    res = list(s)
    for i in range(len(res)):
        c = res[i]
        if c in """:/_#?;@&=+$,"[]<>%\n\\""":
            res[i] = '_%02X' % ord(c)
    return ''.join(res)


def unquote(s):
    """Undo the effects of quote(). Based heavily on urllib.parse.unquote()."""
    mychr = chr
    myatoi = int
    list = s.split('_')
    res = [list[0]]
    myappend = res.append
    del list[0]
    for item in list:
        if item[1:2]:
            try:
                myappend(mychr(myatoi(item[:2], 16)) + item[2:])
            except ValueError:
                myappend('_' + item)
        else:
            myappend('_' + item)
    return "".join(res)

它们似乎在管理模板渲染过程中的某个地方被调用,但是我无法弄清楚在何处/多久一次/所有位置,因此我决定做一个快速的猴子补丁来确定它是否值得追求。解决方案:我将quote()unquote()中的所有下划线更改为quote中问题字符列表中的下划线,例如...

    '_%02X'中的
  • quote()成为'.%02X'
  • split('_')中的
  • unquote()成为split('.')
  • myappend('_' + item)中的
  • unquote()成为myappend('.' + item)

执行此操作后,管理员可以正常工作,并且似乎附加到相关字段上的编辑图标的链接指向正确的模型实例,因此我可以通过单击铅笔图标进行编辑,而不会收到错误消息如上所述。

所有这些,我似乎找不到能够安全地覆盖这两种方法的方法。我真的不希望更改主键来消除下划线,因为数据库中有很多链接模型,而且看起来这将是一个巨大的痛苦。该修补程序似乎更容易且更可靠,并且鉴于它在Django的早期版本中可以正常工作,所以我认为实现它不是一个坏主意。

那么,如何覆盖这些方法?或者,作为一个相关问题,我可以在模型的__str__方法中做些什么来缓解此问题?我会比开始编写覆盖Django admin内部构件的自定义类快得多。如果没有其他解决方案,我需要一些帮助来适当地重组数据库以调整主键,但是我可以说这些键在我正在运行的运行Django 1.11.6的“旧”站点上可以正常使用和Python 2.7.9(与当前的Django 2.1.1和Python 3.6.5相比)

请让我知道是否可以提供更多信息。谢谢!!

1 个答案:

答案 0 :(得分:0)