【问题标题】:Django: reverse() and get_absolute_url() returns different output for same object?Django:reverse() 和 get_absolute_url() 为同一个对象返回不同的输出?
【发布时间】:2017-09-20 08:29:54
【问题描述】:

当与平面页面 reverse()get_abolute_url() 一起使用时,返回不同的输出:

>>> about = FlatPage.objects.get(id=2)
>>> 
>>> about
<FlatPage: /about-us/ -- About us page>
>>>
>>> about.url
>>> '/about-us/'
>>>
>>> about.get_absolute_url()
'/about-us/'
>>>
>>>
>>> reverse('django.contrib.flatpages.views.flatpage', args=[about.url])
'/%2Fabout-us/'    ## from where %2F comes from ?
>>>

这是整个网站的urls.py

from django.conf.urls import url, include
from django.contrib import admin
from django.contrib .flatpages import urls as flatpage_urls
# from . import blog

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include(flatpage_urls)),
]

虽然,我可以访问http://127.0.0.1:8000/about-us/ 的关于页面。 %2F 来自哪里?

我期待这两种方法都应该返回相同的输出。这是怎么回事?

更新:

这里是flatpages/urls.py

from django.conf.urls import url
from django.contrib.flatpages import views

urlpatterns = [
    url(r'^(?P<url>.*)$', views.flatpage, name='django.contrib.flatpages.views.flatpage'),
]

更新 2:

将 urls.py 更新为:

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    # url(r'', include(flatpage_urls)),
]

urlpatterns += [
    url(r'^(?P<url>.*/)$', views.flatpage),
]

【问题讨论】:

  • 这很奇怪。 %2F 是 '/' 的 url 编码。它在某处增加了一个额外的斜线。
  • 您的flatpage_urls 中有什么内容?
  • 你有没有发现什么奇怪的东西?是默认的,我没改过
  • 其实没有,什么都看不到。尝试将 URI 设置为 about-us 并按照文档 url(r'^(?P&lt;url&gt;.*/)$', ...), 在 url 模式中添加斜杠 reverse 现在给你什么?
  • 仍然得到 %2F

标签: python django django-flatpages


【解决方案1】:

在我看来,您正试图在另一个 URL 中插入一个 URL,这看起来很奇怪。

来自您的代码:

reverse('django.contrib.flatpages.views.flatpage', args=[about.url])

您还澄清了about.url 包含/about-us/。此字符串将被引用并插入 URL:

http://hostname.example/<here>/

或者:

http://hostname.example/%2Fabout-us%2F/

我不明白为什么你没有看到最后一个 %2F。

【讨论】:

  • 如果我将url(r'', include(flatpage_urls)) 更改为url(r'^page', include(flatpage_urls)),那么get_absolute_url() 将返回"/about-us/",而reverse() 返回"/page/about"。你觉得这合适吗?如果这对你来说似乎很好,请启发我。你会怎么做呢?
  • 如果您向我们展示about.url 的值可能会有所帮助。而不是我们猜测。
  • about.url 返回/about-us/
  • 我不明白为什么您在开始和结束时并不总是得到 %2F。但是,如果您希望 reverse 每次都能正常工作,则需要传递值,而不是 URL。 reverse('django.contrib.flatpages.views.flatpage', args=['about-us'])
  • 我不能说我真的理解这个平面页面的东西。
【解决方案2】:

django.contrib.flatpages 显然与带有 args 或 kwargs 的 reverse() 不兼容。预期用途是使用其自定义标签:

{% load flatpages %}
{% get_flatpages as flatpages %}
<ul>
    {% for page in flatpages %}
        <li><a href="{{ page.url }}">{{ page.title }}</a></li>
    {% endfor %}
</ul>

来源Flatpages > Getting a list of FlatPage objects in your templates

为什么是 %2f

FlatPage.get_absolute_url() 仅返回 self.url 字段中的任何内容,在您的示例中,该字段是由斜杠括起来的字符串,即“/about-us/”。

def get_absolute_url(self):
    # Handle script prefix manually because we bypass reverse()
    return iri_to_uri(get_script_prefix().rstrip('/') + self.url)

另一方面,reverse() 调用 _reverse_with_prefix(),这会在 URL 前加上一个斜杠 /,从而生成 //about-us/。然后,它错误地将双斜杠确定为尝试重写架构,因此它将第二个斜杠替换为 URL ASCII 代码 %2f 以中和它。

不幸的是,FlatPage.url 的表单验证器要求冒犯前导 /

def clean_url(self):
    url = self.cleaned_data['url']
    if not url.startswith('/'):
        raise forms.ValidationError(
            ugettext("URL is missing a leading slash."),
            ...

您可以通过使用不带斜线的前缀来解决它,例如:

url(r'^pages', include(django.contrib.flatpages.urls))

但这也将匹配pagesabout-us/。如果您像 r'^' 一样完全删除前缀,_reverse_with_prefix() 将添加前缀 / 以避免相对链接。

您可以像 https://docs.djangoproject.com/en/1.11/ref/contrib/flatpages/#using-the-urlconf 中的第三个示例一样对 URL 进行硬编码,但这违背了在 flatpages 表中管理 URL 的目的。

from django.contrib.flatpages import views

urlpatterns += [
    url(r'^about-us/$', views.flatpage, {'url': '/about-us/'}, name='about'),
    url(r'^license/$', views.flatpage, {'url': '/license/'}, name='license'),
]

【讨论】:

    猜你喜欢
    • 2015-09-13
    • 2014-02-13
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多