본문 바로가기

문돌이 존버/Django 스터디

장고(Django), URL Dispatcher와 정규표현식

반응형
본 글은 Holix의 "리액트와 함께 장고 시작하기 Complete" 강의를 듣고 작성한 일지입니다.

URL Dispatcher

URL Dispatcher는 한 마디로 정리해서 "특정 URL 패턴 -> View"의 리스트를 가리킵니다. 프로젝트/settings.py 에서 최상위 URLConf 모듈을 지정하는 것인데, 최초의 urlpatterns 로부터 include 를 통해 트리(Tree) 구조로 확장합니다.

# settings.py
ROOT_URLCONF = '프로젝트명.urls'
# 프로젝트/urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('accounts.urls')),
    path('blog1/', include('blog1.urls')),
]

HTTP 요청이 들어올 때마다 등록된 urlpatterns 상의 매핑 리스트를 처음부터 순차적으로 훑으며 URL 매칭을 시도합니다. 이때 매칭이 되는 URL Rule이 다수 존재하더라도, 처음 Rule만을 사용하고 매칭되는 것이 없을 경우 404 Page Not Found 응답이 발생됩니다.

path()와 re_path()

django.urls.path()는 장고에서 기본으로 지원하는 Path Converters로 정규표현식 기입을 간소화했습니다(물론 만능은 아닙니다). 또 개별적으로 자주 사용하는 패턴을 Converter로 등록하면 재활용면에서 편리하겠죠.

아래는 년도(year)를 쿼리 파라미터로 넘겨주었을 때를 가정한 것입니다.

# urls.py
from django.urls import path, re_path

urlpatterns = [
    path('articles/<int:year>/', views.year_archive), # 숫자 1개든, 2개든 모두 년도로 인식
    re_path(r'^articles/(?P<year>[0-9]{4}/$', views.year_archive), # 4개 연속된 숫자만 year라는 파라미터로 views.py에 넘겨줌
]

참고로 장고에서 제공하는 Path Converters는 아래와 같습니다.

1. IntConverter -> r"[0-9]+"
2. StringConverter -> r"[^/]+"
3. UUIDConverter -> r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
- [0-9a-f]는 16진수를 가리킴
- 하이푼(-)까지 포함하여 총 36 글자
4. SlugConverter(StringConverter 상속) -> r"[-a-zA-Z0-9_]+"
5. PathConverter(StringConverter 상속) -> r".+"
https://docs.djangoproject.com/en/3.2/topics/http/urls/

위에서 잠깐 언급한 Converter를 커스터마이징은 아래와 같이 설정할 수 있습니다.

# app/urls.py
from . import views
from django.urls import path, re_path, register_converter

# customize converter
class YearConverter:
    regex = r"20\d{2}"

    def to_python(self, value): # url로부터 추출한 문자열을 뷰에 넘겨주기 전에 변환
        return int(value)
    def to_url(self, value): # url reverse시 호출
        return str(value)

register_converter(YearConverter, 'year') # converter 이름 지정

urlpatterns = [
    ...
    path('archives/<year:year>/', views.archives_year), # 앞의 year는 converter
]

마지막으로 URL Reverse를 위해 namespace를 설정하는 방법을 소개하고 마무리하겠습니다. 각 앱마다 path 이름이 동일한 경우가 있을 수 있습니다.

예를 들어, 아래처럼 app1에서도 path 이름이 "post_list"이고, app2에서도 동일하게 "post_list"일 수 있습니다.

# app1/urls.py
urlpatterns = [
    path('', views.post_list, name='post_list'),
]

# app2/urls.py
urlpatterns = [
    path('', views.post_detail, name='post_list'),
]

이때 URL Reverse를 하게 되면 어느 앱에 속한 path인지 헷갈리기 때문에 app_name 을 지정하는 방법이 있습니다. 꼭 앱 이름이 아니라 다른 이름을 지정해도 되지만 보통 앱 이름을 그대로 따라합니다.

# 앱/urls.py
app_name = '앱 이름'
728x90
반응형