2014-02-13 41 views
2

我遇到了一个问题,模板url反转是冒号冒号和括号字符。我希望这些字符在锚标记的href属性中保持未转义状态。它曾经在django 1.3中以这种方式表现,但升级到1.6时,我注意到这不符合我的意愿。模板url反转转义surt参数

我有什么:

surt = 'http://(gov/' 
browse_domain = 'gov' 
... in template ... 
<a href="{% url 'nomination.views.url_surt' project.project_slug surt %}">{{ browse_domain }}</a> 

这产生了:

<a href="/nomination/eth2008/surt/http%3A//%28gov/">gov</a> 

正如你所看到的,结肠:和左括号(字符转义在url href属性。我不想那样。

我想要什么:

surt = 'http://(gov/' 
browse_domain = 'Gov' 
... in template ... 
<a href="{% url 'nomination.views.url_surt' project.project_slug surt %}">{{ browse_domain }}</a> 

这产生了:

<a href="/nomination/eth2008/surt/http://(gov/">gov</a> 

任何人都知道如何让这些字符从当我在我的锚标记倒车逃逸的网址?

回答

1

注意:下面的答案是错误的。 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)。这并不完美,但它适用于我们的用例。