Параметры необязательного URL-адреса Django
У меня есть URL Django, как это:
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
Проблема в том, что я хочу, чтобы параметр project_id
был необязательным.
Я хочу /project_config/
и /project_config/12345abdce/
быть равноценными шаблоны URL, так что если project_id
будет принят, то я могу использовать его.
На данный момент, я получаю 404, когда я получаю доступ к URL без параметра project_id
.
Ответы
Ответ 1
Есть несколько подходов.
Одним из них является использование группы без захвата в регулярном выражении: (?:/(?P<title>[a-zA-Z]+)/)?
Создание Regex Django URL-токена необязательно
Другой, более простой способ - иметь несколько правил, которые соответствуют вашим потребностям, и все они указывают на одно и то же представление.
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),
)
Имейте в виду, что, по вашему мнению, вам также необходимо установить значение по умолчанию для необязательного параметра URL, иначе вы получите сообщение об ошибке:
def foo(request, optional_parameter=''):
# Your code goes here
Ответ 2
Вы можете использовать вложенные маршруты
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")
])),
])),
]
Это намного больше DRY (скажем, вы хотели переименовать product
kwarg в product_id
, вам нужно только изменить строку 4, и это повлияет на приведенные ниже URL-адреса.
Отредактировано для Django 1.8 и выше
Ответ 3
Еще проще использовать:
(?P<project_id>\w+|)
"(a | b)" означает a или b, поэтому в вашем случае это будет один или несколько символов слова (\ w +) или ничего.
Итак, это будет выглядеть так:
url(
r'^project_config/(?P<product>\w+)/(?P<project_id>\w+|)/$',
'tool.views.ProjectConfig',
name='project_config'
),
Ответ 4
Думаю, я добавлю немного ответа.
Если у вас несколько определений URL-адресов, вам придется указывать каждый из них отдельно. Таким образом, вы теряете гибкость при вызове reverse, поскольку один обратный будет ожидать параметра, а другой - нет.
Другой способ использования регулярного выражения для размещения необязательного параметра:
r'^project_config/(?P<product>\w+)/((?P<project_id>\w+)/)?$'
Ответ 5
Django> версия 2.0:
Подход, по сути, идентичен подходу, приведенному в "Томита". Затрагивается, однако, синтаксис:
# 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
...
Используя path()
вы также можете передать дополнительные аргументы представлению с необязательным аргументом kwargs
типа dict
. В этом случае вашему представлению не понадобится значение по умолчанию для атрибута project_id
:
...
path(
'project_config/<product>/',
views.get_product,
kwargs={'project_id': None},
name='project_config'
),
...
Как это сделать в самой последней версии Django, смотрите в официальных документах об отправке URL.
Ответ 6
Джанго = 2,2
urlpatterns = [
re_path(r'^project_config/(?:(?P<product>\w+)/(?:(?P<project_id>\w+)/)/)?$', tool.views.ProjectConfig, name='project_config')
]