简体   繁体   English

Django 可选的 url 参数

[英]Django optional url parameters

I have a Django URL like this:我有一个像这样的 Django URL:

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

views.py:视图.py:

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

The problem is that I want the project_id parameter to be optional.问题是我希望project_id参数是可选的。

I want /project_config/ and /project_config/12345abdce/ to be equally valid URL patterns, so that if project_id is passed, then I can use it.我想/project_config//project_config/12345abdce/是同样有效的网址格式,因此,如果project_id通过,那么我就可以使用它。

As it stands at the moment, I get a 404 when I access the URL without the project_id parameter.目前,当我访问没有project_id参数的 URL 时,我得到 404。

There are several approaches.有几种方法。

One is to use a non-capturing group in the regex: (?:/(?P<title>[a-zA-Z]+)/)?一种是在正则表达式中使用非捕获组: (?:/(?P<title>[a-zA-Z]+)/)?
Making a Regex Django URL Token Optional 使正则表达式 Django URL 令牌可选

Another, easier to follow way is to have multiple rules that matches your needs, all pointing to the same view.另一种更容易遵循的方法是拥有多个符合您需求的规则,所有规则都指向同一个视图。

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),
)

Keep in mind that in your view you'll also need to set a default for the optional URL parameter, or you'll get an error:请记住,在您的视图中,您还需要为可选的 URL 参数设置默认值,否则会出现错误:

def foo(request, optional_parameter=''):
    # Your code goes here

You can use nested routes您可以使用嵌套路由

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

This is a lot more DRY (Say you wanted to rename the product kwarg to product_id , you only have to change line 4, and it will affect the below URLs.这更 DRY(假设您想将product kwarg 重命名为product_id ,您只需更改第 4 行,它将影响以下 URL。

Edited for Django 1.8 and above为 Django 1.8 及以上版本编辑

Django > 2.0 version : Django > 2.0 版本

The approach is essentially identical with the one given in Yuji 'Tomita' Tomita's Answer .该方法与Yuji 'Tomita' Tomita's Answer 中给出的方法基本相同。 Affected, however, is the syntax:但是,受影响的是语法:

# 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
    ...

Using path() you can also pass extra arguments to a view with the optional argument kwargs that is of type dict .使用path()您还可以将额外的参数传递给带有dict类型的可选参数kwargs 的视图 In this case your view would not need a default for the attribute project_id :在这种情况下,您的视图不需要属性project_id的默认值:

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

For how this is done in the most recent Django version , see the official docs about URL dispatching .有关如何在最新的 Django 版本中完成此操作,请参阅有关 URL 调度的官方文档

Even simpler is to use:更简单的是使用:

(?P<project_id>\w+|)

The "(a|b)" means a or b, so in your case it would be one or more word characters (\\w+) or nothing. "(a|b)" 表示 a 或 b,因此在您的情况下,它将是一个或多个单词字符 (\\w+) 或什么都没有。

So it would look like:所以它看起来像:

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

Thought I'd add a bit to the answer.以为我会在答案中添加一点。

If you have multiple URL definitions then you'll have to name each of them separately.如果您有多个 URL 定义,则必须分别命名它们。 So you lose the flexibility when calling reverse since one reverse will expect a parameter while the other won't.因此,您在调用 reverse 时失去了灵活性,因为一个反向需要一个参数,而另一个则不需要。

Another way to use regex to accommodate the optional parameter:另一种使用正则表达式来容纳可选参数的方法:

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

Django = 2.2姜戈 = 2.2

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

Use ?用 ? work well, you can check on pythex .运行良好,您可以检查pythex Remember to add the parameters *args and **kwargs in the definition of the view methods记得在视图方法的定义中添加参数 *args 和 **kwargs

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM