J'ai une URL Django comme ceci:
url(
r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$',
'tool.views.ProjectConfig',
name='project_config'
),
views.py:
def ProjectConfig(request, product, project_id=None, template_name='project.html'):
...
# do stuff
Le problème est que je veux que le paramètre project_id
soit facultatif.
Je veux que /project_config/
et /project_config/12345abdce/
soient des modèles d'URL également valides, de sorte que ifproject_id
soit transmis, alors je peux l'utiliser. .
En l'état actuel des choses, je reçois un 404 lorsque j'accède à l'URL sans le paramètre project_id
.
Il y a plusieurs approches.
La première consiste à utiliser un groupe sans capture dans la regex: (?:/(?P<title>[a-zA-Z]+)/)?
Création d'une expression régulière Django URL Token Facultatif
Une autre façon, plus facile à suivre, consiste à avoir plusieurs règles correspondant à 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),
url(r'^project_config/(?P<product>\w+)/(?P<project_id>\w+)/$', views.foo),
)
N'oubliez pas que, dans votre vue, vous devrez également définir une valeur par défaut pour le paramètre URL facultatif. Sinon, vous obtiendrez une erreur:
def foo(request, optional_parameter=''):
# Your code goes here
Vous pouvez utiliser des 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 DRY (supposons que vous vouliez renommer la product
kwarg en product_id
, il vous suffit de modifier la ligne 4, ce qui affectera les URL ci-dessous.
Edité pour Django 1.8 et supérieur
Encore plus simple est d'utiliser:
(?P<project_id>\w+|)
Le "(a | b)" signifie a ou b, donc dans votre cas, ce serait un ou plusieurs caractères Word (\ w +) ou rien.
Donc, cela ressemblerait à:
url(
r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
'tool.views.ProjectConfig',
name='project_config'
),
Je pensais ajouter un peu à la réponse.
Si vous avez plusieurs définitions d'URL, vous devrez les nommer séparément. Vous perdez donc la flexibilité lorsque vous appelez en sens inverse, car un retour en arrière attend un paramètre alors que l'autre ne le fera pas.
Une autre façon d’utiliser regex pour prendre en charge le paramètre facultatif:
r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'
Django> version 2.0 :
L'approche est essentiellement identique à celle donnée dans Réponse de Yuji 'Tomita' Tomita . Affecté, cependant, est la syntaxe:
# 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
...
En utilisant path()
, vous pouvez aussi passer des arguments supplémentaires à une vue avec l'argument facultatif kwargs
de type dict
. Dans ce cas, votre vue n'aurait pas besoin de valeur par défaut pour l'attribut project_id
:
...
path(
'project_config/<product>/',
views.get_product,
kwargs={'project_id': None},
name='project_config'
),
...
Pour savoir comment cela est effectué dans la version la plus récente de Django , voir l'officiel docs sur l'acheminement d'URL .
Django = 2,2
urlpatterns = [
re_path(r'^project_config/(?:(?P<product>\w+)/(?:(?P<project_id>\w+)/)/)?$', tool.views.ProjectConfig, name='project_config')
]