web-dev-qa-db-fra.com

Django paramètres d'URL facultatifs

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.

144
Darwin Tech

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
343

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

36
Jacob Valenta

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'
),
23
Juan José Brown

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+)/)?$'
9
tarequeh

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 .

8
jojo

Django = 2,2

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