200

我有一个这样的 Django URL:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),

视图.py:

def ProjectConfig(request, product, project_id=None, template_name='project.html'):
    ...
    # do stuff

问题是我希望project_id参数是可选的。

我想要/project_config/并且/project_config/12345abdce/是同样有效的 URL 模式,这样如果 project_id通过了,那么我可以使用它。

就目前而言,当我在没有project_id参数的情况下访问 URL 时得到 404。

4

7 回答 7

441

有几种方法。

一种是在正则表达式中使用非捕获组: (?:/(?P<title>[a-zA-Z]+)/)?
Making a Regex Django URL Token Optional

另一种更容易遵循的方法是拥有多个符合您需求的规则,所有规则都指向同一个视图。

urlpatterns = patterns('',
    url(r'^project_config/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/$', views.foo),
    url(r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$', views.foo),
)

请记住,在您的视图中,您还需要为可选的 URL 参数设置默认值,否则您会收到错误消息:

def foo(request, optional_parameter=''):
    # Your code goes here
于 2013-01-16T04:03:10.923 回答
40

Django > 2.0 版本

该方法与Yuji 'Tomita' Tomita's Answer中给出的方法基本相同。然而,受影响的是语法:

# URLconf
...

urlpatterns = [
    path(
        'project_config/<product>/',
        views.get_product, 
        name='project_config'
    ),
    path(
        'project_config/<product>/<project_id>/',
        views.get_product,
        name='project_config'
    ),
]


# View (in views.py)
def get_product(request, product, project_id='None'):
    # Output the appropriate product
    ...

使用path()您还可以使用类型为的可选参数将额外参数传递给视图。在这种情况下,您的视图不需要属性的默认值:kwargsdictproject_id

    ...
    path(
        'project_config/<product>/',
        views.get_product,
        kwargs={'project_id': None},
        name='project_config'
    ),
    ...

有关如何在最新的 Django 版本中完成此操作,请参阅有关 URL 调度的官方文档

于 2019-01-24T14:13:38.413 回答
38

您可以使用嵌套路由

姜戈 <1.8

urlpatterns = patterns(''
    url(r'^project_config/', include(patterns('',
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include(patterns('',
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ))),
    ))),
)

Django >=1.8

urlpatterns = [
    url(r'^project_config/', include([
        url(r'^$', ProjectConfigView.as_view(), name="project_config")
        url(r'^(?P<product>\w+)$', include([
            url(r'^$', ProductView.as_view(), name="product"),
            url(r'^(?P<project_id>\w+)$', ProjectDetailView.as_view(), name="project_detail")
        ])),
    ])),
]

这要干得多(假设您想将productkwarg 重命名为product_id,您只需更改第 4 行,它将影响以下 URL。

为 Django 1.8 及更高版本编辑

于 2014-03-24T22:51:25.473 回答
32

更简单的是使用:

(?P<project_id>\w+|)

“(a|b)”表示 a 或 b,因此在您的情况下,它将是一个或多个单词字符 (\w+) 或什么都没有。

所以它看起来像:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),
于 2014-07-07T12:38:39.627 回答
10

以为我会在答案中添加一点。

如果您有多个 URL 定义,则必须分别命名它们。所以你在调用 reverse 时失去了灵活性,因为一个 reverse 会需要一个参数,而另一个不会。

另一种使用正则表达式来容纳可选参数的方法:

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'
于 2014-02-18T00:51:56.697 回答
4

姜戈 = 2.2

urlpatterns = [
    re_path(r'^project_config/(?:(?P<product>\w+)/(?:(?P<project_id>\w+)/)/)?$', tool.views.ProjectConfig, name='project_config')
]
于 2019-04-03T16:01:46.307 回答
0

利用 ?工作得很好,你可以检查pythex。记得在视图方法的定义中添加参数 *args 和 **kwargs

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')
于 2020-05-03T17:52:23.303 回答