Django:reverse() 和 get_absolute_url() 为同一个对象返回不同的输出?

Django: reverse() and get_absolute_url() returns different output for same object?

提问人:Cody 提问时间:4/24/2017 最后编辑:Cody 更新时间:9/12/2017 访问量:1210

问:

当与简单页面一起使用并返回不同的输出时: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),
]
python django django-flatpages

评论

0赞 stonemetal 4/24/2017
这很奇怪。%2F 是“/”的 url 编码。它在某处捡起了一个额外的斜杠。
0赞 Andrey Shipilov 4/24/2017
你的里面有什么?flatpage_urls
0赞 Cody 4/24/2017
你觉得有什么奇怪的吗?这是默认的,我没有改变一点
0赞 Andrey Shipilov 4/24/2017
其实没有,什么也没看到。尝试将 URI 设置为并按照文档在 url 模式中添加斜杠现在给你什么?about-usurl(r'^(?P<url>.*/)$', ...),reverse
0赞 Cody 4/24/2017
仍然得到 %2F

答:

0赞 Penguin Brian 4/24/2017 #1

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

从您的代码:

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

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

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

艺术

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

但是,我不明白为什么您没有看到最后的%2F。

评论

0赞 Cody 4/24/2017
如果我更改为 ,则 get_absolute_url() 返回 as 返回 。这对你来说合适吗?如果这对你来说很好,请启发我。你会怎么做?url(r'', include(flatpage_urls))url(r'^page', include(flatpage_urls))"/about-us/"reverse()"/page/about"
0赞 Penguin Brian 4/24/2017
如果你向我们展示它的价值是什么,它可能会有所帮助。而不是我们猜测。about.url
0赞 Cody 4/24/2017
about.url 返回/about-us/
0赞 Penguin Brian 4/24/2017
我不明白为什么你并不总是在开始和结束时得到一个 %2F。但是,如果希望 reverse 每次都能正常工作,则需要传递值,而不是 URL。reverse('django.contrib.flatpages.views.flatpage', args=['about-us'])
0赞 Penguin Brian 4/24/2017
然而,我不能说我真的理解这个简单页面的东西。
0赞 nonzero 9/12/2017 #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>

简单页面 > 获取模板中的 FlatPage 对象列表

为什么选择 %2f

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

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

另一方面,调用 ,在 URL 前面加上斜杠,从而导致 .然后,它错误地将双斜杠确定为尝试重写架构,因此它将第二个斜杠替换为 URL ASCII 代码以中和它。reverse()_reverse_with_prefix()///about-us/%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))

但这也会匹配.如果像 一样完全删除前缀,则会以 a 为前缀,以避免相对链接。pagesabout-us/r'^'_reverse_with_prefix()/

您可以像 https://docs.djangoproject.com/en/1.11/ref/contrib/flatpages/#using-the-urlconf 中的第三个示例一样对 URL 进行硬编码,但这违背了在简单页面表中管理 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'),
]