it-swarm.com.ru

Django необязательные параметры URL

У меня есть 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.

141
Darwin Tech

Есть несколько подходов.

Одним из них является использование группы без захвата в регулярном выражении: (?:/(?P<title>[a-zA-Z]+)/)?
Создание регулярного выражения 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
336
Yuji 'Tomita' Tomita

Вы можете использовать вложенные маршруты

Джанго <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 (скажем, вы хотите переименовать kwarg product в product_id, вам нужно только изменить строку 4, и это повлияет на приведенные ниже URL-адреса.

Отредактировано для Django 1.8 и выше

36
Jacob Valenta

Еще проще использовать:

(?P<project_id>\w+|)

"(A | b)" означает a или b, поэтому в вашем случае это будет один или несколько символов Word (\ w +) или ничего.

Так это будет выглядеть так:

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

Думаю, я бы немного добавил к ответу.

Если у вас есть несколько определений URL, вам нужно будет назвать каждое из них отдельно. Таким образом, вы теряете гибкость при вызове реверса, поскольку один реверс будет ожидать параметр, а другой - нет.

Еще один способ использования регулярных выражений для размещения необязательного параметра:

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

Django> версия 2.0 :

Подход, по сути, идентичен тому, который указан в Yuji 'Tomita' Tomita's Answer . Затрагивается, однако, синтаксис:

# 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, вы также можете передать дополнительные аргументы в представление с dict в качестве необязательного аргумента. В этом случае вашему представлению не потребуется значение по умолчанию для атрибута project_id:

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

Как это сделать в последней версии Django , смотрите официальный документы об отправке URL .

5
jojo

Джанго = 2,2

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