ChatGPT解决这个技术问题 Extra ChatGPT

Django 可选 url 参数

我有一个这样的 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 模式,以便 if project_id 被传递,then 我可以使用它。

就目前而言,当我访问没有 project_id 参数的 URL 时,我得到一个 404。


l
l0b0

有几种方法。

一种是在正则表达式中使用非捕获组:(?:/(?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

投票支持多路线选项。 +1
@Yuji - 你不能通过命名每个 url 模式来解决反转问题吗?
我们可以给每个视图命名吗?
@Yuji'Tomita'Tomita 我知道,所以不幸的是,尤金的问题的答案是,不,我们不能理智地拥有多个具有相同名称的视图,即使我们将它们作为获取可选参数的一种方式来实现。
@eugene 是的,我们可以有两个同名的 url,根据 args,反转会巧妙地选择适用的
j
jojo

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(),您还可以将 pass extra arguments to a viewdict 类型的可选参数 kwargs 结合使用。在这种情况下,您的视图不需要属性 project_id 的默认值:

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

在最新的 Django 版本中如何做到这一点,请参阅 the official docs about URL dispatching


我认为您在代码中混淆了 project_id 和 product_id ,对吗?
@AndreasBergström 非常感谢您指出这一点!你说得对!匆忙更正,但稍后会再看第二次。希望现在一切都好!在默认使用 dict 的情况下,路径中还有 project_id。这可能会导致看似奇怪的行为,因为将始终使用 dict 中提供的参数(如果我没记错的话)。
@jojo这是否意味着第二个选项中的 'project_config/foo/bar' 会自动将 {'project_id': 'bar'} kwargs 传递给视图?
J
Jacob Valenta

您可以使用嵌套路由

姜戈 <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")
        ])),
    ])),
]

这更 DRY(假设您想将 product kwarg 重命名为 product_id,您只需更改第 4 行,它将影响以下 URL。

为 Django 1.8 及更高版本编辑


嵌套很好。此外,它更清楚地分隔代码中的不同 URL 部分(由于使用缩进)
嵌套的问题是,如果你有多个可选参数,那么你最终不会是 DRY,因为例如,如果有 3 个可选参数,你就有 8 种不同的可能 URL 组合。您必须处理参数 1 出现,参数 1 未出现但参数 2 出现,以及参数 1 和 2 未出现但参数 3 出现。 URL 段落将比具有多个可选参数的单个字符串更难阅读。对可选参数子字符串使用符号常量将使其非常易于阅读,并且只有一个 URL。
我认为您是对的,但这更多是由于视图/ URL 设计不佳所致。这个例子可以修改得更好。
'平面优于嵌套'
J
Juan José Brown

更简单的是使用:

(?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'
),

我喜欢这个解决方案的简单性,但要注意:这样做,视图仍会收到参数的值,即 None。这意味着您不能为此依赖视图签名中的默认值:您必须在内部显式测试它并进行分配。
这就是我一直在寻找的 =)
如果 project_id 不存在,最后一个斜杠呢?
你可以只添加一个?在斜线之后或仅在 project_id 模式中包含斜线
t
tarequeh

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

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

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

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'

在 Django 1.6 中,这对我来说是一个异常。我会远离它Reverse for 'edit_too_late' with arguments '()' and keyword arguments '{'pk': 128}' not found. 1 pattern(s) tried: ['orders/cannot_edit/((?P<pk>\\d+)/)?$']
A
AzizAhmad

姜戈 = 2.2

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

f
franciscorode

利用 ?运行良好,您可以查看 pythex。记得在视图方法的定义中添加参数 *args 和 **kwargs

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