템플릿

템플릿 (Templates)

웹 프레임워크인 Django는 HTML을 동적으로 생성해야 하는데, 가장 흔한 방법이 템플릿이에요. 템플릿은 출력할 HTML의 정적인 부분과, 동적 콘텐츠가 들어갈 위치를 설명하는 특별한 문법을 함께 담고 있어요. Django 프로젝트는 여러 템플릿 엔진을 설정할 수 있고, 기본으로 자체 템플릿 언어(Django Template Language, DTL)와 대안으로 널리 쓰이는 Jinja2를 지원해요.

출처: Django 공식 문서 - Templates

템플릿의 기본 개념

Django는 백엔드와 무관하게 템플릿을 로딩하고 렌더링하는 표준 API를 정의해요. 로딩(loading)은 주어진 식별자로 템플릿을 찾아 전처리하고, 보통 메모리상의 표현으로 컴파일하는 일이에요. 렌더링(rendering)은 템플릿을 컨텍스트 데이터와 인터폴레이션해서 결과 문자열을 돌려주는 일이에요.

Django 템플릿 언어(DTL)는 Django 1.8 전까지는 유일한 내장 옵션이었어요. 나름 규칙이 있고 특이한 점이 좀 있지만 좋은 템플릿 라이브러리예요. 다른 백엔드를 선택할 절실한 이유가 없다면, 특히 플러그 가능한 애플리케이션을 만들어 템플릿을 배포하려 한다면 DTL을 쓰세요. django.contrib.admin처럼 템플릿을 포함한 contrib 앱들도 DTL을 사용해요.

한 가지 꼭 기억해야 할 경고가 있어요. 템플릿 시스템은 신뢰할 수 없는 작성자로부터 안전하지 않아요. 사용자가 직접 템플릿을 제공하게 허용하면 XSS 공격을 하거나 템플릿 변수의 민감 정보에 접근할 수 있기 때문에, 사용자가 자신의 템플릿을 올리게 하면 안 돼요.

Django 템플릿 언어 문법

템플릿은 컨텍스트로 렌더링돼요. 변수는 컨텍스트에서 값을 찾아 치환되고, 태그는 실행되며, 그 외의 것은 그대로 출력돼요. 문법은 네 가지 구성요소로 이루어져요.

변수

변수는 컨텍스트에서 값을 출력해요. {{}}로 감싸요.

My first name is {{ first_name }}. My last name is {{ last_name }}.

컨텍스트가 {'first_name': 'John', 'last_name': 'Doe'}라면 "My first name is John. My last name is Doe."로 렌더링돼요. 사전 조회, 속성 조회, 리스트 인덱스 조회는 점(.) 표기법으로 해요.

{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}

변수가 callable로 해석되면 템플릿 시스템이 인자 없이 호출하고 그 결과를 사용해요.

필터

필터는 변수와 태그 인자의 값을 변환해요.

{{ django|title }}

컨텍스트의 django'thewebframeworkforperfectionistswithdeadlines'라면 "The Web Framework For Perfectionists With Deadlines"로 렌더링돼요. 인자를 받는 필터도 있어요.

{{ my_date|date:"Y-m-d" }}

엔진, 템플릿, 컨텍스트

django.template.Engine은 Django 템플릿 시스템의 인스턴스를 캡슐화해요. Django 프로젝트 밖에서 DTL을 쓰려면 Engine을 직접 인스턴스화하는 것이 주된 이유예요. django.template.backends.django.DjangoTemplatesEngine을 Django의 템플릿 백엔드 API에 맞춰 주는 얇은 래퍼예요.

django.template.Template는 컴파일된 템플릿을 나타내요. Engine.get_template()이나 Engine.from_string()으로 얻을 수 있어요. django.template.Context는 컨텍스트 데이터에 더해 일부 메타데이터를 담고, Template.render()에 전달돼요. django.template.RequestContextContext의 서브클래스로 현재 HttpRequest를 저장하고 템플릿 컨텍스트 프로세서를 실행해요.

로더와 컨텍스트 프로세서

템플릿 로더(template loader)는 템플릿을 찾아 로딩하고 Template 객체를 돌려주는 역할을 해요. Django는 여러 내장 로더를 제공하고 커스텀 로더도 지원해요.

컨텍스트 프로세서(context processor)는 현재 HttpRequest를 받아 렌더링 컨텍스트에 추가할 데이터가 담긴 dict를 돌려주는 함수예요. 주된 용도는 모든 템플릿이 공유하는 공통 데이터를, 뷰마다 반복해서 코드를 넣지 않고도 컨텍스트에 추가하는 일이에요.

템플릿 엔진 구성

템플릿 엔진은 TEMPLATES 설정으로 구성해요. 이 설정은 엔진마다 하나씩, 설정 항목의 리스트예요. 기본값은 비어 있고, startproject가 만든 settings.py는 더 유용한 값을 정의해요.

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            # ... some options here ...
        },
    },
]

BACKEND는 Django의 템플릿 백엔드 API를 구현한 템플릿 엔진 클래스의 점 표기 파이썬 경로예요. 내장 백엔드는 django.template.backends.django.DjangoTemplatesdjango.template.backends.jinja2.Jinja2예요. 대부분의 엔진이 파일에서 템플릿을 로딩하므로, 각 엔진의 최상위 구성은 두 가지 공통 설정을 포함해요.

  • DIRS — 엔진이 템플릿 소스 파일을 찾을 디렉토리 목록(검색 순서대로)
  • APP_DIRS — 설치된 애플리케이션 안에서 템플릿을 찾을지 여부

드물지만 같은 백엔드를 다른 옵션으로 여러 개 구성할 수도 있는데, 그럴 때는 각 엔진에 고유한 NAME을 정해야 해요. OPTIONS에는 백엔드별 설정이 들어가요.

템플릿 로딩하기

django.template.loader 모듈은 템플릿을 로딩하는 두 함수를 정의해요.

  • get_template(template_name, using=None) — 주어진 이름의 템플릿을 로딩해 Template 객체를 돌려줘요. 각 엔진을 순서대로 시도하다가, 못 찾으면 TemplateDoesNotExist, 문법이 잘못됐으면 TemplateSyntaxError를 일으켜요. 특정 엔진으로 검색을 제한하려면 using 인자에 엔진의 NAME을 넘겨요.
  • select_template(template_name_list, using=None)get_template()과 같지만 템플릿 이름의 리스트를 받아, 순서대로 시도해 처음으로 존재하는 템플릿을 돌려줘요.

TemplateDoesNotExist 예외는 템플릿을 찾지 못했을 때 일어나며, 디버그 페이지의 템플릿 부검(postmortem)을 채우기 위해 backend, tried 같은 선택 인자를 받을 수 있어요. tried에는 찾을 때 시도한 소스들의 (origin, status) 튜플 목록이 들어가요.

더 알아보기 (Learn more)