Django paramètres d'url optionnels

j'ai une url Django comme celle-ci:

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

et mon views.py:

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

Le problème est que je veux le project_id paramètre facultatif. Je voudrais que /project_config/ et /project_config/12345abdce/ soient tous deux des modèles d'url également valables, de sorte que si project_id est passé, alors je peux l'utiliser. En ce moment, j'obtiens une erreur 404 si j'essaie d'accéder à l'url sans le project_id paramètre.

130
demandé sur CIGuy 2013-01-16 07:46:35

4 réponses

Il y a plusieurs approches.

L'un est d'utiliser un regex de fantaisie... (?:/(?P<title>[a-zA-Z]+)/)?

rendre un jeton D'URL de Django Regex optionnel

un autre moyen plus facile à suivre est d'avoir plusieurs règles qui correspondent à vos besoins, toutes pointant vers la même vue.

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

gardez à l'esprit que dans votre vue vous aurez également besoin de définir une valeur par défaut pour le paramètre optionnel URL, ou vous obtenir une erreur:

def foo(request, optional_parameter=''):
    # Your code goes here
311
répondu Yuji 'Tomita' Tomita 2017-05-23 11:47:29

vous pouvez utiliser les routes imbriquées

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

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

C'est beaucoup plus sec (dites que vous vouliez renommer le product kwarg en product_id , vous n'avez qu'à changer la ligne 4, et cela affectera les URLs ci-dessous.

Édité pour Django 1,8 et au-dessus de

35
répondu Jacob Valenta 2016-06-12 19:24:17

encore plus simple à utiliser:

(?P<project_id>\w+|)

La "(a|b)" a ou b, donc dans votre cas il s'agirait d'un ou plusieurs caractères de mot (\w+) ou rien.

donc ça ressemblerait à:

url(
    r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
    'tool.views.ProjectConfig',
    name='project_config'
),
21
répondu Juan José Brown 2014-07-07 12:38:39

a pensé que je voudrais ajouter un peu à la réponse.

si vous avez plusieurs définitions D'URL, vous devrez les nommer séparément. Ainsi, vous perdez la flexibilité lorsque vous appelez reverse car un reverse attendra un paramètre alors que l'autre ne le fera pas.

une autre façon d'utiliser regex pour accommoder le paramètre optionnel:

r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'
8
répondu tarequeh 2014-02-18 00:51:56