Django URL 라우팅 시스템 완벽 가이드

Django 라우팅 시스템 완벽 가이드

1. 웹 요청 처리 과정

브라우저에 URL을 입력하면 다음과 같은 과정이 수행됩니다:

  • 도메인을解析하고 DNS를 통해 IP 주소 조회
  • 얻은 IP 주소로 서버와 TCP 연결 수립
  • HTTP 요청(GET, POST 등)을 서버로 전송
  • 서버가 요청을 처리하고 응답 반환
  • 브라우저가 응답을 받아 화면에 렌더링

2. Django 요청 처리 흐름

Django는 WSGI 기반의 프레임워크로, 다음과 같은 단계로 요청을 처리합니다:

  1. 웹 서버: Apache, Nginx 등이 요청을 수신
  2. WSGI 인터페이스: Django와 웹 서버 간의桥梁 역할
  3. 미들웨어: 인증, 로깅, 요청/응답 변환 등 전처리
  4. URL 라우팅: URL 패턴을 기반으로视图 함수 매칭
  5. 뷰 처리: 요청 객체 생성 후视图 함수 호출
  6. 모델層: 데이터베이스 상호작용
  7. 템플릿 렌더링: 동적 HTML 생성
  8. 응답 반환: HttpResponse 객체 클라이언트에 전송

3. URL 설정 기초

3.1 Django 1.x 문법

Django 1.x 버전에서는 url() 함수를 사용합니다:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^home/$', views.home_view, name='home'),
    url(r'^about/$', views.about_view),
]

매개변수 구성:

  • 정규식: URL 패턴 매칭
  • 뷰 함수: 요청 처리 함수
  • 인자: 딕셔너리 형태의 추가 데이터
  • 별칭: 템플릿에서 참조용 이름

3.2 Django 2.x 이상 문법

2.x 버전부터는 path()re_path() 함수 제공:

from django.urls import path, re_path
from . import views

urlpatterns = [
    path('articles/2024/', views.special_case),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    re_path(r'^posts/(?P<slug>[\w-]+)/$', views.post_detail),
]

4. 경로 변환기(Path Converter)

Django 2.0부터 URL 매칭에 사용되는 변환기가 도입되었습니다. path()는 정규식을 지원하지 않으나, 다양한 내장 변환자를 제공합니다.

4.1 지원 변환자 유형

path('user/<int:user_id>/', views.user_detail),    # 정수
path('category/<str:category_name>/', views.category),  # 문자열
path('file/<path:file_path>/', views.file_view),  # 경로(含斜杠)
path('post/<slug:slug>/', views.post_view),      # 슬러그
path('uuid/<uuid:article_id>/', views.article),   # UUID
path('price/<float:price>/', views.price_view),  # 실수

4.2 변환자 사용 예시

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('product/<int:product_id>/', views.product_detail),
]
# views.py
from django.http import HttpResponse

def product_detail(request, product_id):
    return HttpResponse(f'Product ID: {product_id}')

4.3 커스텀 변환자 생성

# converters.py
class FourDigitYearConverter:
    regex = '[0-9]{4}'
    
    def to_python(self, value):
        return int(value)
    
    def to_url(self, value):
        return f'{value:04d}'
# urls.py
from django.urls import register_converter
from .converters import FourDigitYearConverter

register_converter(FourDigitYearConverter, 'yyyy')
urlpatterns = [
    path('archive/<yyyy:year>/', views.archive_year),
]

5. 정규식 그룹 매칭

5.1无名 그룹(위치 인자)

괄호로 묶인 정규식 매칭 결과가 위치 인자로 뷰 함수에 전달됩니다:

# urls.py
from django.urls import re_path
from . import views

urlpatterns = [
    re_path(r'^item/(\d+)/$', views.item_detail),
]
# views.py
def item_detail(request, item_id):
    return HttpResponse(f'Item: {item_id}')

5.2有名 그룹(키워드 인자)

그룹에 이름을 지정하여 키워드 인자로 전달:

# urls.py
from django.urls import re_path
from . import views

urlpatterns = [
    re_path(r'^book/(?P<book_id>\d+)/(?P<chapter>\d+)/$', views.chapter_view),
]
# views.py
def chapter_view(request, book_id, chapter):
    return HttpResponse(f'Book {book_id}, Chapter {chapter}')

6. 역방향解析(Reverse Resolution)

URL 별칭으로부터 실제 URL을 생성하는 메커니즘입니다.

6.1 역방향解析의 필요성

  • URL 패턴 변경 시 개별 링크 수정 불필요
  • 코드 결합도 감소
  • 템플릿과 뷰에서 일관된 URL 참조 가능

6.2 뷰 함수에서의 사용

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('user/profile/', views.profile, name='user_profile'),
    path('user/edit/<int:user_id>/', views.edit_profile, name='edit_profile'),
]
# views.py
from django.urls import reverse
from django.shortcuts import redirect

def some_view(request):
    # 간단한 역방향解析
    url = reverse('user_profile')
    
    # 파라미터가 있는 경우
    edit_url = reverse('edit_profile', args=[42])
    
    return redirect(url)

6.3 템플릿에서의 사용

<a href="{% url 'user_profile' %}">마이페이지</a>
<a href="{% url 'edit_profile' user.id %}">프로필 편집</a>

{#有名 그룹의 경우#}
<a href="{% url 'edit_profile' user_id=user.id %}">편집</a>

7. 라우트 분기(Include)

애플리케이션별로 URL 설정을 분리하여 관리할 수 있습니다.

7.1 프로젝트 구조

myproject/
├── manage.py
├── myproject/
│   ├── settings.py
│   └── urls.py          # 메인 URL 설정
├── blog/
│   ├── urls.py          #_blog URL 설정
│   └── views.py
└── shop/
    ├── urls.py          # 상점 URL 설정
    └── views.py

7.2 개별 앱 URL 설정

# blog/urls.py
from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    path('', views.index, name='index'),
    path('post/<int:post_id>/', views.post_detail, name='detail'),
]
# shop/urls.py
from django.urls import path
from . import views

app_name = 'shop'

urlpatterns = [
    path('', views.product_list, name='list'),
    path('product/<int:product_id>/', views.product_detail, name='detail'),
]

7.3 메인 URL에서 분기

# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls', namespace='blog')),
    path('shop/', include('shop.urls', namespace='shop')),
]

8. 네임스페이스

여러 앱에서 동일한 URL 별칭을 사용할 때 충돌을 방지합니다.

8.1 앱 레벨 네임스페이스

각 앱의 urls.py에서 app_name 변수로 정의:

# myapp/urls.py
from django.urls import path
from . import views

app_name = 'myapp'  # 네임스페이스 이름 설정

urlpatterns = [
    path('index/', views.index, name='index'),
    path('detail/', views.detail, name='detail'),
]

8.2 인스턴스 네임스페이스

같은 앱을 여러 인스턴스로 사용할 경우:

path('primary/', include('myapp.urls', namespace='primary')),
path('secondary/', include('myapp.urls', namespace='secondary')),

8.3 네임스페이스 활용

# 뷰에서 현재 네임스페이스 확인
def my_view(request):
    namespace = request.resolver_match.namespace
    return HttpResponse(f'Current namespace: {namespace}')

# 템플릿에서 특정 네임스페이스 참조
<a href="{% url 'blog:index' %}">블로그</a>
<a href="{% url 'shop:index' %}">상점</a>

9. 버전별 차이점

9.1 Django 1.x vs 2.x 이상

특징 Django 1.x Django 2.x 이상
주요 함수 url() path()
정규식 지원 첫 번째 인자가 정규식 path()는不支持, re_path() 사용
변환자 미지원 5+ 내장 변환자 제공

9.2 Django 2.x vs 3.x

  • Django 3.x 신규 변환자: <uuid:>, <path:>
  • 기능 개선: 변환자 성능 최적화 및 유효성 검사 강화
  • 하위 호환성: 3.x 변환자가 2.x에서도 대부분 동작

9.3 정규식 패턴 비교

# Django 1.x
from django.conf.urls import url
urlpatterns = [
    url(r'^article/(?P<year>[0-9]{4})/$', views.year_archive),
]

# Django 2.x
from django.urls import path
urlpatterns = [
    path('article/<int:year>/', views.year_archive),
]

# Django 3.x (정규식 필요 시)
from django.urls import re_path
urlpatterns = [
    re_path(r'^article/(?P<year>[0-9]{4})/$', views.year_archive),
]

10. 추가 설정

10.1 자동 슬래시 추가 제어

# settings.py
APPEND_SLASH = True  # 기본값: True

10.2 정적 파일 설정

# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / 'static',
]

10.3 템플릿 디렉토리 설정

# settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
            ],
        },
    },
]

11. 실제 사용 예시

# 프로젝트 전체 구조 예시
# myproject/
#   urls.py (메인 라우트)
#   settings.py
# blog/
#   models.py
#   views.py
#   urls.py
#   apps.py

# blog/urls.py
from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('<int:post_id>/', views.post_detail, name='post_detail'),
    path('category/<str:category>/', views.post_by_category, name='post_by_category'),
    path('tag/<slug:tag>/', views.post_by_tag, name='post_by_tag'),
]

# blog/views.py
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from .models import Post

def post_list(request):
    posts = Post.objects.all()
    return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, post_id):
    post = get_object_or_404(Post, pk=post_id)
    
    # 역방향解析로 관련 URL 생성
    edit_url = reverse('blog:post_edit', args=[post_id])
    
    return render(request, 'blog/post_detail.html', {'post': post, 'edit_url': edit_url})

이상으로 Django의 URL 라우팅 시스템에 대한 comprehensive 가이드를 마무리합니다. 라우팅은 Django 애플리케이션의 핵심 구성 요소로, 적절한 설계가 프로젝트의 확장성과 유지보수성에 큰 영향을 미칩니다.

태그: Django python url-routing web-development backend

6월 24일 17:52에 게시됨