Django 라우팅 시스템 완벽 가이드
1. 웹 요청 처리 과정
브라우저에 URL을 입력하면 다음과 같은 과정이 수행됩니다:
- 도메인을解析하고 DNS를 통해 IP 주소 조회
- 얻은 IP 주소로 서버와 TCP 연결 수립
- HTTP 요청(GET, POST 등)을 서버로 전송
- 서버가 요청을 처리하고 응답 반환
- 브라우저가 응답을 받아 화면에 렌더링
2. Django 요청 처리 흐름
Django는 WSGI 기반의 프레임워크로, 다음과 같은 단계로 요청을 처리합니다:
- 웹 서버: Apache, Nginx 등이 요청을 수신
- WSGI 인터페이스: Django와 웹 서버 간의桥梁 역할
- 미들웨어: 인증, 로깅, 요청/응답 변환 등 전처리
- URL 라우팅: URL 패턴을 기반으로视图 함수 매칭
- 뷰 처리: 요청 객체 생성 후视图 함수 호출
- 모델層: 데이터베이스 상호작용
- 템플릿 렌더링: 동적 HTML 생성
- 응답 반환: 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)
# 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)
<a href="{% url 'user_profile' %}">마이페이지</a>
<a href="{% url 'edit_profile' user.id %}">프로필 편집</a>
{#有名 그룹의 경우#}
<a href="{% url 'edit_profile' user_id=user.id %}">편집</a>
애플리케이션별로 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 애플리케이션의 핵심 구성 요소로, 적절한 설계가 프로젝트의 확장성과 유지보수성에 큰 영향을 미칩니다.