Django 선택적 URL 매개 변수


161

다음과 같은 장고 URL이 있습니다.

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 통과, 다음 그것을 사용할 수 있습니다.

현재로서는 project_id매개 변수 없이 URL에 액세스하면 404가 표시됩니다 .

답변:


381

몇 가지 접근 방식이 있습니다.

하나는 정규식에서 캡처하지 않는 그룹을 사용하는 것입니다 (?:/(?P<title>[a-zA-Z]+)/)?
. 정규식 장고 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

68
다중 경로 옵션에 투표하십시오. +1
Burhan Khalid

4
@Yuji-각 URL 패턴의 이름을 지정하여 역전 문제를 해결할 수 없습니까?
Ted

8
모든 뷰에 동일한 이름을 부여 할 수 있습니까?
eugene

2
@ Yuji'Tomita'Tomita 알고 있습니다. 유진의 질문에 대한 대답은 불행히도, 선택적 매개 변수를 얻는 방법으로 구현하더라도 동일한 이름으로 여러 뷰를 가질 수는 없습니다.
nnyby

2
@eugene 예, 이름이 같은 두 개의 URL을 가질 수 있습니다. 리버스 링은 인수에 따라 적용 할 수있는 URL을 스마트하게 선택합니다.
Arpit Singh

37

중첩 된 경로를 사용할 수 있습니다

장고 <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")
        ))),
    ))),
)

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

이것은 훨씬 더 건조합니다 ( productkwarg의 이름을으로 바꾸려면 product_id4 줄만 변경하면 아래 URL에 영향을 미칩니다.

Django 1.8 이상용으로 편집


1
중첩이 좋습니다. 또한 들여 쓰기를 사용하여 코드에서 다른 URL 섹션을보다 명확하게 구분합니다.
Patrick

중첩의 문제점은 여러 개의 선택적 매개 변수가있는 경우 예를 들어 3 개의 선택적 매개 변수를 사용하면 8 개의 가능한 URL 조합이 있으므로 DRY가되지 않습니다. 매개 변수 1 발생, 매개 변수 1 발생하지 않지만 매개 변수 2 발생 및 매개 변수 1과 2 발생하지 않고 매개 변수 3 발생을 처리해야합니다. URL 단락은 여러 개의 선택적 매개 변수가있는 단일 문자열보다 읽기가 훨씬 어렵습니다. 선택적 매개 변수 하위 문자열에 기호 상수를 사용하면 매우 쉽게 읽을 수 있으며 하나의 URL 만 있습니다.
Bogatyr

나는 당신이 옳다고 생각하지만,보기 / URL 디자인이 좋지 않은 결과입니다. 이 예제는 훨씬 나아지기 위해 재 작업 될 수 있습니다.
Jacob Valenta

'평지가 중첩보다 낫다'
pjdavis

30

더 간단한 방법은 다음과 같습니다.

(?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'
),

9
나는이 솔루션의 단순함을 좋아하지만주의하십시오 : 그렇게하면 뷰는 여전히 인수 값을받습니다 None. 이를 위해 뷰의 서명에서 기본값을 사용할 수 없다는 것을 의미합니다. 내부에서 명시 적으로 테스트하고 결과를 할당해야합니다.
Anto

이것은 내가) = 찾고 있었다이다
마이크 브라이언 올리베라

3
project_id가없는 경우 마지막 슬래시는 어떻게 되나요?
iamkhush 2016 년

당신은 그냥 추가 할 수 있습니까? 슬래시 후 또는 project_id 패턴에 슬래시 포함
Juan José Brown

18

장고> 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()하면 유형이 선택적 인수 인 뷰에 추가 인수를 전달할 수도 있습니다 . 이 경우 뷰에는 속성의 기본값이 필요하지 않습니다 .kwargsdictproject_id

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

최신 Django 버전 에서이 작업을 수행하는 방법 은 URL 디스패치에 대한 공식 문서를 참조하십시오 .


1
코드에서 project_id와 product_id를 섞은 것 같습니다.
Andreas Bergström

@ AndreasBergström 지적 해 주셔서 감사합니다! 당신은 이것에 대해 아주 옳습니다! 서둘러 수정했지만 나중에 두 번째로 살펴볼 것입니다. 지금은 괜찮기를 바랍니다! 도 있었다 project_id를 사용하여 기본의 경우 경로에 여전히가 dict. 에 제공된 인수 dict가 항상 사용되므로 (정확하게 기억한다면) 이상한 행동으로 이어질 수 있습니다 .
jojo

@jojo 두 번째 옵션의 'project_config / foo / bar'가 { 'project_id': 'bar'} kwargs를 자동으로 뷰에 전달한다는 의미입니까?
Original BBQ 소스

9

대답에 약간을 추가 할 것이라고 생각했습니다.

URL 정의가 여러 개인 경우 각각의 이름을 개별적으로 지정해야합니다. 따라서 리버스를 호출 할 때 유연성을 잃을 수 있습니다. 한 리버스에는 매개 변수가 필요하고 다른 한 리버스는 그렇지 않습니다.

선택적 매개 변수를 수용하기 위해 정규 표현식을 사용하는 다른 방법 :

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

2
장고 1.6에서는 이것이 예외입니다. 나는 멀리 떨어져있을거야Reverse for 'edit_too_late' with arguments '()' and keyword arguments '{'pk': 128}' not found. 1 pattern(s) tried: ['orders/cannot_edit/((?P<pk>\\d+)/)?$']
Patrick

2

장고 = 2.2

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

0

사용하다 ? 잘 작동하면 pythex를 확인할 수 있습니다 . 뷰 메소드의 정의에 매개 변수 * args 및 ** kwargs를 추가해야합니다.

url('project_config/(?P<product>\w+)?(/(?P<project_id>\w+/)?)?', tool.views.ProjectConfig, name='project_config')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.