Django可选的url参数

Dar*_*ech 150 python django django-urls django-views

我有一个像这样的Django网址:

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

和我的views.py:

def ProjectConfig(request, product, project_id=None, template_name='project.html'):
    ...
    # do stuff
Run Code Online (Sandbox Code Playgroud)

问题是我希望project_id参数是可选的.我想这样,project_id并且/project_config/都是同样有效的url模式,所以IF /project_config/12345abdce/传递,然后我可以使用它.就目前而言,如果我尝试访问没有project_id参数的url,我会得到404 .

Yuj*_*ita 357

有几种方法.

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

另一种更容易理解的方法是使多个规则符合您的需求,所有规则都指向同一个视图.

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),
)
Run Code Online (Sandbox Code Playgroud)

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

def foo(request, optional_parameter=''):
    # Your code goes here
Run Code Online (Sandbox Code Playgroud)

  • 投票选择多路线选项.+1 (64认同)
  • 我们可以给每个视图同名吗? (8认同)
  • @Yuji - 你能不能通过命名每个url模式来解决逆转问题? (4认同)
  • @ Yuji'Tomita'Tomita我知道,所以对eugene的问题的答案很遗憾,即使我们将它们作为一种获取可选参数的方式实现它们,我们也不能理智地拥有同名的多个视图. (2认同)
  • @eugene是的,我们可以有两个具有相同名称的URL,反向转换将根据参数自动选择合适的URL (2认同)

Jac*_*nta 36

您可以使用嵌套路由

Django <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")
        ))),
    ))),
)
Run Code Online (Sandbox Code Playgroud)

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")
        ])),
    ])),
]
Run Code Online (Sandbox Code Playgroud)

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

编辑Django 1.8及以上版本


Jua*_*own 27

更简单的是使用:

(?P<project_id>\w+|)
Run Code Online (Sandbox Code Playgroud)

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

所以它看起来像:

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

  • 我喜欢这个解决方案的简单性,但要注意:通过这样做,视图仍将接收参数的值,该值将为"None".这意味着你不能依赖于视图签名中的默认值:你必须在里面明确地测试它并分配结果. (9认同)
  • 如果project_id不存在,最后一个斜杠怎么办? (2认同)

joj*_*ojo 13

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
    ...
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 我认为您在代码中混淆了project_id 和product_id,对吧? (2认同)

tar*_*ueh 9

以为我会在答案中添加一些内容.

如果您有多个URL定义,那么您必须分别为每个URL定义.因此,在调用reverse时会失去灵活性,因为一个反向将期望一个参数而另一个反之则不会.

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

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'
Run Code Online (Sandbox Code Playgroud)

  • 在Django 1.6中,这对我来说是一个例外.我会远离它`反向'edit_too_late',参数'()'和关键字参数'{'pk':128}'找不到.1个模式试过:['orders/cannot_edit /((?P <pk> \\ d +)/)?$']` (2认同)

Azi*_*mad 5

姜戈 = 2.2

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