Django URL 命名空间 - 模板必须知道它的命名空间?

Django URL namespaces - the template has to know its namespace?

我一直在修补(我的第一个)Django 项目,该项目从 Django 1.6 开始,最近刚刚转移到 Django 1.8。我也一直在研究 Django 模式和最佳实践,学习我应该如何构建它:-)

我的项目有几个子应用程序和一个典型的主应用程序 urls.py,其行如下:

 (r'', include('noc.apps.frontpage.urls')),

在每个应用程序中,我都在所有 URL 名称前加上应用程序名称前缀,例如frontpage_edit_page 并在整个模板中使用 {% url %} 在视图之间引用。

然后我阅读了有关 URL 名称空间的信息,并认为我可以对我的 URL 名称进行去丑化处理。正如我最初解释的那样,如果我在主 urls.py 中为每个 include() 添加一个命名空间,一切都会像以前一样运行,因为引用的 URL 名称将全部由 'local' 应用程序。但它似乎不是那样工作的。

主要是这个urls.py:

(r'', include('noc.apps.frontpage.urls', namespace='frontpage', app_name='frontpage')),

这在应用程序中 urls.py:

 url(r'^frontpage/edit/(?P<slug>[A-Za-z0-9]+)$', views.edit_page, name='front_page_edit_page'),

{% url 'front_page_edit_page' slug=page.slug %} 在该应用程序内的模板中,我得到一个 NoReverseMatch 异常,尝试了 0 URLs。

我能找到的所有示例都在讨论使用命名空间为 URL 加上前缀 - frontpage:front_page_edit_page 但是 1) 这对 URL 上的先前应用程序前缀有何改进姓名?和 2) 你怎么可能有同一个应用程序的两个实例,这应该是一个好处......所以我假设这是为了链接 between 应用程序,而不是 个应用程序中。

那么我缺少什么?我是否也需要在我的视图函数中嵌入 app_name 或命名空间?的确,如果我确实在我的所有 URL 名称前加上命名空间,即使在应用程序中,我也会得到一个呈现的页面,但这似乎没有意义。

你打算这样做的方式确实是将命名空间添加到 URL 标记;

{% url 'frontpage:edit_page' slug='SLUG' %}

但是最好像这样构建您的主项目 URls 文件;

urlpatterns = patterns(
    '',
    url(r'^admin/', include(admin.site.urls)),  # NOQA
    url(r'frontpage', include('noc.apps.frontpage.urls', namespace='frontpage', app_name='frontpage')),

这样你就可以在主URLs文件中指定每个应用程序的路径,避免重复;

urlpatterns = patterns(
    'noc.apps.frontpage.views',
    url(r'^edit/(?P<slug>[A-Za-z0-9]+)$', 'edit_page', name='edit_page'),

有了这个,您可以为所有应用程序引入一个 RESTful URL 结构,这样您最终会得到类似的东西;

urlpatterns = patterns(
    '',
    url(r'^admin/', include(admin.site.urls)),  # NOQA
    url(r'frontpage/', include('noc.apps.frontpage.urls', namespace='frontpage', app_name='frontpage')),
    url(r'contact/', include('noc.apps.contact.urls', namespace='contact', app_name='contact')),
    url(r'myapp/', include('noc.apps.myapp.urls', namespace='myapp', app_name='myapp')),

那么您所有的应用程序都可以遵循类似的结构;

urlpatterns = patterns(
    'noc.apps.contact.views',
    url(r'^$', 'index', name='index'),
    url(r'^add/$', 'add', name='add'),
    url(r'^edit/(?P<slug>[A-Za-z0-9]+)$', 'edit', name='edit'),

urlpatterns = patterns(
    'noc.apps.myapp.views',
    url(r'^$', 'index', name='index'),
    url(r'^add/$', 'add', name='add'),
    url(r'^edit/(?P<slug>[A-Za-z0-9]+)$', 'edit', name='edit'),

可以使用顶级命名空间实现 frontpage 的多个实例;

urlpatterns = patterns(
    '',
    url(r'^admin/', include(admin.site.urls)),  # NOQA
    url(r'frontpage/', include('noc.apps.frontpage.urls', namespace='frontpage1', app_name='frontpage')),
    url(r'frontpage/', include('noc.apps.frontpage.urls', namespace='frontpage2', app_name='frontpage')),

这样您应该能够定位顶级实例命名空间,然后是像这样的应用程序命名空间;

{% url 'frontpage1:frontpage:edit_page' slug='SLUG' %}
{% url 'frontpage2:frontpage:edit_page' slug='SLUG' %}

但是如果你想让你的模板链接更通用,我相信你可以省略顶级命名空间,django 将解析到你必须添加到请求对象的当前应用程序。这个在Reversing Namespaced URLs

末尾有详细说明

试试这个

(r'', include('noc.apps.frontpage.urls', namespace = 'abc')),

然后在您的模板中:

{% url 'abc:frontpage:front_page_edit_page' slug=page.slug %}

供大家参考。

这对我有用,Django 2.2.2

# project urls.py
# DjpollsConfig is my app config
from djpolls.apps import DjpollsConfig
djpolls_app_name = DjpollsConfig.name

urlpatterns = [
    path(djpolls_app_name, include('djpolls.urls', namespace='djpolls_app_name'))
]
# app urls.py
from django_proj.urls import djpolls_app_name
app_name = djpolls_app_name
# app template
{% url 'djpolls_app_name:detail' question.id %}

希望对您有所帮助!