Django URL 라우팅, 뷰 응답 및 요청 처리, 템플릿 시스템 심층 분석

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 %}

커스텀 템플릿 확장 기능

내장 기능 외에도 개발자가 직접 필터, 태그 등을 정의할 수 있습니다.

설치 조건

  1. 해당 앱이 INSTALLED_APPS에 등록되어 있어야 함
  2. 앱 내부에 templatetags라는 이름의 파이썬 패키지 생성
  3. 패키지 내 임의의 .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 %}

태그: Django URL routing view functions Template language Custom template tags

7월 6일 22:53에 게시됨