23

我一直在试图弄清楚如何look:like:this在 Django URLConf 中定义一个嵌套的 URL 命名空间(which )。

在此之前,我想出了如何创建一个基本的 URL 命名空间,并提出了这个简单的示例片段,其中包含您可能放入urls.py文件中的内容:

from django.conf.urls import patterns, include, url

# you can only define a namespace for urls when calling include():

app_patterns = patterns('',
    url(r'^(?P<pk>[\w\-]+)/$', 'yourapp.views.your_view_function',
        name="your-view"),
)

urlpatterns = patterns('',
    url(r'^view-function/', include(app_patterns,
        namespace='yournamespace', app_name='yourapp')),
)

"""

    You can now use the namespace when you refer to the view, e.g. a call
    to `reverse()`:

    # yourapp/models.py

    from django.core.urlresolvers import reverse

    # ...

    class MyModel(models.Model):

        def get_absolute_url(self):
            return reverse('signalqueue:exception-log-entry', kwargs=dict(pk=self.pk))

"""

... w/r/t Django 文档的推论在这种情况下根本没有帮助。虽然 Django 的文档在所有其他方面都很棒,而且这是一个例外,但关于定义嵌套 URL 命名空间的信息就更少了。

我没有发布我的意大利面条式的尝试†来解决这个问题,我想我可能会问是否有人拥有或知道一个直接有说服力和/或不言自明的 URLconf 示例,该示例定义了一个他们可以共享的嵌套命名空间。

具体来说,我对视图前缀的嵌套部分感到好奇:它们需要安装 Django 应用程序吗?

†)对于好奇,这里有一个(可能有点难以理解)的例子:http: //imgur.com/NDn9H。我试图在底部以红色和绿色打印出 URL,testapp:views:<viewname>而不是仅仅命名为testapp:<viewname>.

4

2 回答 2

35

它的工作原理相当直观。include具有另一个命名空间的 urlconfinclude将导致嵌套命名空间。

## urls.py
nested2 = patterns('',
   url(r'^index/$', 'index', name='index'),
)

nested1 = patterns('',
   url(r'^nested2/', include(nested2, namespace="nested2"),
   url(r'^index/$', 'index', name='index'),
)   

urlpatterns = patterns('',
   (r'^nested1/', include(nested1, namespace="nested1"),
)

reverse('nested1:nested2:index') # should output /nested1/nested2/index/
reverse('nested1:index') # should output /nested1/index/

这是保持网址井井有条的好方法。我想我能给出的最好建议是记住include可以直接获取一个patterns对象(如我的示例中所示),这使您可以使用单个urls.py视图并将视图拆分为有用的命名空间,而无需创建多个 urls 文件。

于 2012-10-02T02:51:40.277 回答
11

更新 2 (2019-10-09)

正如 eugene 评论的那样,UPDATE 1 不再适用于更新版本的 Django,后者需要在包含时app_name在 a 中定义。urls.py

在 GitHub 上,我创建了一个 Django 项目( myproject),其中包含几个应用程序 (productsbooks),以演示如何创建嵌套命名空间。总之,各种urls.py看起来像这样:

# myproject/urls.py
from django.urls import include, path
from products import urls as products_urls
from products import views

urlpatterns = [
    path("", views.site_home, name="home"),
    path("products/", include(products_urls, namespace="products"),)
]
# products/urls.py
from django.urls import include, path
from books import urls as books_urls
from . import views

app_name = "products"

urlpatterns = [
    path("", views.index, name="product_index"),
    path("books/", include(books_urls, namespace="books")),
]
# books/urls.py
from django.urls import path
from . import views

app_name = "books"

urlpatterns = [
    path("", views.index, name="book_index"),
    path("<slug:book_slug>/", views.detail, name="book_detail"),
]

因此,您可以像这样使用这些嵌套的 URL 名称:

reverse("products:books:book_index")
# '/products/books/'

reverse("products:books:book_detail", kwargs={"book_slug": "my-book"})
# '/products/books/my-book/'

更新 1

Django 2.0 引入了两个相关的变化。首先,urls()函数现在在 中django.urls,所以urls.py上面示例的第一行将是:

from django.urls import include, url

其次,它引入了path()函数作为不需要正则表达式的路径的更简单替代方案。使用它,示例urls.py将如下所示:

from django.urls import include, path

nested2 = [
   path('index/', 'index', name='index'),
]   

nested1 = [
   path('nested2/', include(nested2, namespace='nested2')),
   path('index/', 'index', name='index'),
]   

urlpatterns = [
   path('nested1/', include(nested1, namespace='nested1')),
]

原始答案

虽然 Yuji 的回答是正确的,但请注意django.conf.urls.patterns不再存在(自 Django 1.10 起),而是使用普通列表。

同样的例子urls.py现在应该是这样的:

from django.conf.urls import include, url

nested2 = [
   url(r'^index/$', 'index', name='index'),
]   

nested1 = [
   url(r'^nested2/', include(nested2, namespace='nested2')),
   url(r'^index/$', 'index', name='index'),
]   

urlpatterns = [
   url(r'^nested1/', include(nested1, namespace='nested1')),
]   

仍然像这样使用:

reverse('nested1:nested2:index') # should output /nested1/nested2/index/
reverse('nested1:index') # should output /nested1/index/
于 2017-04-17T20:47:10.410 回答