注意:下面的答案是错误的。 urllib.quote(safe =':()')的确可以保证这些安全角色不会转义。 Django发生了其他事情,导致这个问题,我仍然不知道它在哪里。
在Django 1.6中,模板中的任何网址逆转在呈现为HTML之前将首先通过iri_to_uri()
。 在模板调用url reverse {% url %}
原样没有覆盖。
注意this bit斜体文字详述了更改。
这是iri_to_uri()
def iri_to_uri(iri):
"""
Convert an Internationalized Resource Identifier (IRI) portion to a URI
portion that is suitable for inclusion in a URL.
This is the algorithm from section 3.1 of RFC 3987. However, since we are
assuming input is either UTF-8 or unicode already, we can simplify things a
little from the full method.
Returns an ASCII string containing the encoded result.
"""
# The list of safe characters here is constructed from the "reserved" and
# "unreserved" characters specified in sections 2.2 and 2.3 of RFC 3986:
# reserved = gen-delims/sub-delims
# gen-delims = ":"/"/"/"?"/"#"/"["/"]"/"@"
# sub-delims = "!"/"$"/"&"/"'"/"("/")"
# /"*"/"+"/","/";"/"="
# unreserved = ALPHA/DIGIT/"-"/"."/"_"/"~"
# Of the unreserved characters, urllib.quote already considers all but
# the ~ safe.
# The % character is also added to the list of safe characters here, as the
# end of section 3.1 of RFC 3987 specifically mentions that % must not be
# converted.
if iri is None:
return iri
return urllib.quote(smart_str(iri), safe="/#%[]=:;$&()+,!?*@'~")
乍一看,这可能看起来像:
,(
和)
因为它们是作为“安全”传递给urllib.quote()
是从十六进制编码逃脱安全:
_safe_map = {}
for i, c in zip(xrange(256), str(bytearray(xrange(256)))):
_safe_map[c] = c if (i < 128 and c in always_safe) else '%{:02X}'.format(i)
_safe_quoters = {}
def quote(s, safe='/'):
# fastpath
if not s:
if s is None:
raise TypeError('None object cannot be quoted')
return s
cachekey = (safe, always_safe)
try:
(quoter, safe) = _safe_quoters[cachekey]
except KeyError:
safe_map = _safe_map.copy()
safe_map.update([(c, c) for c in safe])
quoter = safe_map.__getitem__
safe = always_safe + safe
_safe_quoters[cachekey] = (quoter, safe)
if not s.rstrip(safe):
return s
return ''.join(map(quoter, s))
如果您按照上面所示的实际方法urllib.quote()
,“安全”实际上意味着那些字符将被转义/引用。起初,我认为'安全'意味着'安全引用'。这引起了我很大的困惑。我想他们的意思是,'安全'与'安全的条款 - RFC-3986的2.2和2.3'一样。也许更精心命名的关键字参数将是谨慎的,但是再一次,有关于urllib
我觉得很尴尬的整个聚宝盆。 After_ಠ
经过大量研究,并且由于我们不想修改Django核心方法,我们的团队决定在模板中进行一些hacky的url构建(非常友好的Django文档strongly eschew)。这并不完美,但它适用于我们的用例。