URL 라우팅 구성과 동적 매핑
Django 애플리케이션의 진입점은 URL 라우터입니다. 사용자의 요청 경로를 기반으로 해당하는 뷰 함수를 찾아 실행합니다. 프로젝트 수준의 urls.py에서 특정 앱의 URL 설정을 포함시키는 구조로 설계됩니다.
from django.urls import path, re_path, include
urlpatterns = [
re_path(r'^my_app/', include('my_app.urls')), # my_app/ 하위 경로는 my_app.urls에서 처리
]
앱 내부의 urls.py에서는 실제 뷰와 연결되는 경로를 정의합니다.
from . import views
urlpatterns = [
path('mytest/2003/', views.my_test, name='mytest_reverse'),
]
정적 경로 외에도 동적 세그먼트를 추출하기 위해 정규 표현식 또는 path()의 변환자 기능을 활용할 수 있습니다.
# 위치 기반 그룹 캡처 (정규식)
re_path(r'^case3/([0-9]{4,})/([0-9]{2})/$', views.case03),
# 명명된 그룹 캡처 (정규식)
re_path(r'^case3/(?P<year>[0-9]{4,})/(?P<month>[0-9]{2})/$', views.case03),
# 내장 변환자 사용 (path)
path('case3/<int:year>/<int:month>/', views.case03),
URL 이름 지정을 통해 하드코딩 없이도 경로 참조가 가능해집니다. 이는 리버스 URL 해석(reverse resolution)에 사용되며 유지보수성을 높입니다.
re_path(
r'^case3/(?P<year>[0-9]{4,})/(?P<month>[0-9]{2})/$',
views.case03,
name='myurl'
)
여러 앱에서 동일한 이름이 중복될 수 있으므로 네임스페이스(namespace)를 사용하여 충돌을 방지합니다.
# 프로젝트 urls.py
path('rbac/', include('rbac.urls', namespace='rbac')),
템플릿 내에서 다음과 같이 사용합니다.
<{% url 'rbac:some-url-name' arg1=value1 arg2=value2 %}>
뷰(Views)를 통한 응답 생성
뷰는 HTTP 요청을 받아 적절한 응답을 반환하는 함수 또는 클래스입니다. 주요 응답 타입은 다음과 같습니다.
HttpResponse
기본적인 문자열 응답을 생성합니다. HTML 콘텐츠나 단순 메시지를 반환할 때 사용됩니다.
from django.http import HttpResponse
def summary_view(request):
return HttpResponse("처리 완료")
render
템플릿 파일을 렌더링하고 컨텍스트 데이터를 삽입한 후 HTML 응답을 반환합니다.
from django.shortcuts import render
def summary_view(request):
context = {'message': 'Hello Django'}
return render(request, 'test.html', context)
JsonResponse
JSON 형식의 응답을 반환합니다. 딕셔너리 외 리스트 등 다른 자료형을 반환하려면 safe=False 옵션이 필요합니다.
from django.http import JsonResponse
def api_view(request):
data = {'status': 'success', 'items': [1, 2, 3]}
return JsonResponse(data, safe=False, json_dumps_params={'ensure_ascii': False})
HTTP 요청 데이터 접근 방법
뷰 함수 내에서 request 객체를 통해 다양한 요청 정보에 접근할 수 있습니다.
def handle_request(request):
print(request.method) # GET, POST 등 요청 메서드
print(request.path) # /my_app/zongjie/
print(request.get_full_path()) # /my_app/zongjie/?a=1&b=2
print(request.GET) # <QueryDict: {'a': ['1'], 'b': ['2']}>
print(request.GET.get('a')) # '1'
print(request.POST) # POST 본문 데이터
print(request.META.get('HTTP_USER_AGENT')) # 요청 헤더 정보
print(request.resolver_match.url_name) # 현재 매칭된 URL 이름
GET 파라미터 조작
쿼리 스트링을 동적으로 수정해야 할 경우 QueryDict의 가변성(mutable) 속성을 활용합니다.
from django.http import QueryDict
def edit_view(request):
# 기존 GET 파라미터 복사 후 수정 가능 상태로 전환
next_params = request.GET.copy()
next_params['next'] = request.path_info
redirect_url = f"{request.path}?{next_params.urlencode()}"
# 이후 redirect_url을 폼이나 링크에 사용
템플릿 엔진과 필터 시스템
Django Template Language(DTL)는 뷰에서 전달된 데이터를 기반으로 동적 HTML을 생성합니다.
템플릿 로드 순서
설정 파일에서 지정된 순서대로 템플릿을 탐색합니다.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 프로젝트 루트 우선
'APP_DIRS': True, # 각 앱의 templates/ 디렉터리 자동 탐색
...
},
]
렌더링 원리
render() 함수는 내부적으로 get_template()을 호출하여 템플릿을 로드하고 컨텍스트와 결합합니다.
from django.template.loader import get_template
# 정적 렌더링
template = get_template('index.html')
html = template.render()
# 동적 렌더링
context = {'name': 'alex'}
html = template.render(context, request)
템플릿 태그와 필터
- {{ variable }}: 변수 출력. 딕셔너리, 리스트, 객체 속성 접근 시 점(.) 표기법 사용
- {{ obj|filter_name:param }}: 내장 필터 적용 예 (
default,truncatechars,date등)
반복문 제어
{% for item in item_list %}
{{ forloop.counter }} {# 1부터 시작 #}
{{ forloop.counter0 }} {# 0부터 시작 #}
{{ forloop.first }} {# 첫 번째 반복인지 여부 #}
{{ forloop.last }} {# 마지막 반복인지 여부 #}
{% endfor %}
조건문
{% if score > 90 %}
우수
{% elif score > 80 %}
보통
{% else %}
미흡
{% endif %}
with 태그
복잡한 표현식의 결과를 변수로 저장하여 재사용합니다.
{% with total=cart.items_cost|add:cart.tax %}
Total: {{ total }}
{% endwith %}
커스텀 템플릿 확장 기능
내장 기능 외에도 개발자가 직접 필터, 태그 등을 정의할 수 있습니다.
설치 조건
- 해당 앱이
INSTALLED_APPS에 등록되어 있어야 함 - 앱 내부에
templatetags라는 이름의 파이썬 패키지 생성 - 패키지 내 임의의
.py파일 생성 (예:custom_tags.py)
코드 예제
from django import template
register = template.Library()
@register.filter
def slice_filter(text):
return text[2:4]
@register.simple_tag
def add_values(a, b):
return a + b
@register.inclusion_tag('role_display.html')
def show_role(age):
role = "초등학생" if age <= 10 else "중학생"
return {'role': role}
템플릿에서 사용법
{% load custom_tags %}
<p>{{ content|slice_filter }}</p>
<p>{% add_values 5 3 %}</p>
<p>{% show_role user_age %}</p>
템플릿 상속과 포함
공통 레이아웃을 효율적으로 관리하기 위한 두 가지 핵심 메커니즘입니다.
상속 (extends)
베이스 템플릿을 확장하여 공통 구조를 유지합니다.
{% extends "base.html" %}
{% block title %}홈페이지{% endblock %}
{% block content %}
{{ block.super }} {# 부모 블록 내용 유지 #}
<h1>고유 콘텐츠</h1>
{% endblock %}
포함 (include)
특정 부분만을 외부 템플릿에서 불러옵니다.
<div class="sidebar">
{% include "snippets/navigation.html" %}
</div>
정적 파일과 스크립트 삽입
자식 템플릿에서 JS/CSS를 추가하려면 부모 템플릿에 확장을 위한 블록을 마련해야 합니다.
{% load static %}
<head>
<link rel="stylesheet" href="{% static 'css/main.css' %}">
{% block extra_css %}{% endblock %}
</head>
<body>
...
<script src="{% static 'js/base.js' %}"></script>
{% block extra_js %}{% endblock %}
</body>
자식 템플릿에서 다음과 같이 오버라이드합니다.
{% block extra_js %}
<script>
$(function() {
console.log("페이지 전용 스크립트");
});
</script>
{% endblock %}
템플릿 문법 이스케이프
DTL 문법 그 자체를 출력해야 할 경우 verbatim 블록을 사용합니다.
{% verbatim %}
<p>사용자 입력: {{ raw_input }}</p>
{% endverbatim %}