python - 如何安全地覆盖 django.contrib.admin.utils quote() 方法?
问题描述
看起来里面的quote()
andunquote()
方法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 管理内部的自定义类早得多。如果没有其他解决方案,我需要一些帮助来正确重组我的数据库以调整主键,但我可以说这些键在我正在处理的“旧”站点上完美运行,该站点运行 Django 1.11.6和 Python 2.7.9(与当前的 Django 2.1.1 和 Python 3.6.5 相比)
如果我可以提供更多信息,请告诉我。谢谢!!
解决方案
这在 django 2.2 中已修复。见https://github.com/django/django/commit/e4df8e6dc021fa472fa77f9b835db74810184748
推荐阅读
- sql-server - JOINing 临时表时多次指定的列
- javascript - 如何在 Google GeoCharts 中使用邮政编码
- javascript - Google Maps API - 根据英里计算缩放
- laravel - 如何在模型本身的 Laravel 中将 unix 时间戳转换为 Carbon 实例?
- scala - 如何使用 Scala 在 Spark 数据框中为每个不同的列值创建行 ID 列
- ios - 使用什么 CIFilter 来获得扫描效果?
- wpf - 使用网格控件调整大小时应用程序内存迅速增加
- c# - Unity 的 GetComponent 通过字符串(或通过从另一个脚本传递的其他方法)
- c# - 如何为 WPF 应用程序和 ASP.net 应用程序创建安装程序?
- c++ - 从另一个程序检查 cin 而无需在 OSX 中等待