wake-up-neo.com

Django optionale URL-Parameter

Ich habe eine Django URL wie diese:

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

Das Problem ist, dass der Parameter project_id Optional sein soll.

Ich möchte, dass /project_config/ Und /project_config/12345abdce/ Gleichermaßen gültige URL-Muster sind, damit ifproject_id Übergeben wird, then I kann es benutzen.

Im Moment erhalte ich eine 404, wenn ich auf die URL ohne den Parameter project_id Zugreife.

144
Darwin Tech

Es gibt verschiedene Ansätze.

Eine ist, eine nicht erfassende Gruppe im regulären Ausdruck zu verwenden: (?:/(?P<title>[a-zA-Z]+)/)?
Regex erstellen Django URL-Token optional

Ein anderer, einfacher zu befolgender Weg besteht darin, mehrere Regeln zu haben, die Ihren Anforderungen entsprechen und alle auf dieselbe Ansicht verweisen.

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

Beachten Sie, dass Sie Ihrer Ansicht nach auch einen Standardwert für den optionalen URL-Parameter festlegen müssen, da sonst eine Fehlermeldung angezeigt wird:

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

Sie können verschachtelte Routen verwenden

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

Dies ist viel mehr DRY (Angenommen, Sie wollten das product kwarg in product_id Umbenennen, Sie müssen nur Zeile 4 ändern, und es wirkt sich auf das aus unter URLs.

Bearbeitet für Django 1.8 und höher

36
Jacob Valenta

Noch einfacher zu bedienen ist:

(?P<project_id>\w+|)

Das "(a | b)" bedeutet "a" oder "b", in Ihrem Fall sind es also ein oder mehrere Wortzeichen (\ w +) oder nichts.

So würde es aussehen:

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

Dachte, ich würde ein bisschen zur Antwort hinzufügen.

Wenn Sie mehrere URL-Definitionen haben, müssen Sie diese einzeln benennen. Sie verlieren also die Flexibilität beim Aufruf von reverse, da ein reverse einen Parameter erwartet, der andere nicht.

Eine andere Möglichkeit, den optionalen Parameter mithilfe von Regex anzupassen:

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

Django> 2.0 Version :

Der Ansatz ist im Wesentlichen identisch mit dem in Yuji 'Tomita' Tomitas Antwort . Betroffen ist jedoch die 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
    ...

Mit path() können Sie auch zusätzliche Argumente an eine Ansicht übergeben mit dem optionalen Argument kwargs vom Typ dict. In diesem Fall würde Ihre Ansicht keine Standardeinstellung für das Attribut project_id Benötigen:

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

Wie das gemacht wird in der neuesten Django version , siehe der Beamte) Dokumente zum URL-Versand .

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