[Django] Template
작성:    
업데이트:
카테고리: Django
태그: BE Framework, Django
Template
- 데이터 표현을 제어하는 도구
- 표현에 관련된 로직
- 사용하는 built-in system : DTL
DTL : Django Template Language
- Django template에서 사용하는 built-in template system
- 조건, 반복, 변수 치환, 필터 등의 기능을 제공
- 단순히 Python이 HTML에 포함된 것이 아니다. 프로그래밍적 로직이 아니라 프레젠테이션을 표현하기 위한 것!!
유의📢 Python처럼 일부 프로그래밍 구조(if, for 등)를 사용할 수 있지만, Python 코드로 실행되는 것이 아니다.
Variable
{{ variable }}
- render()를 사용하여 views.py에서 정의한 변수를 template 파일로 넘겨 사용
- dot(.)를 사용하여 변수 속성에 접근 가능
- render()의 세번째 인자로 {‘key’:value}와 같이 딕셔너리 형태로 넘겨준다. context라고 한다. 여기서 정의한 key에 해당하는 문자열이 template에서 사용 가능한 변수명
# views.py
def greeting(request):
return render(request, 'greeting.html', {'name': 'Alice', })
# templates/greeting.html
...
<h1>안녕하세요. 저는 {{ name }} 입니다.</h1>
...
변수를 사용할 수 있다.
변수명 규칙
- 영어, 숫자와 밑줄(_)의 조합으로 구성
- 밑줄로는 시작 불가
- 공백이나 구두점 문자 또한 사용 불가
context
# views.py
def greeting(request):
context = {
'name': 'Alice',
}
return render(request, 'greeting.html', context)
context 위치에 context 변수를 넣고 위에서 정의해주어도 된다.
context 심화
context에 필요한 자료의 양이 많아진다면 다음과 같이 사용할 수 있다.
def greeting(request):
foods = ['apple', 'banana', 'coconut']
info = {
'name': 'Alice',
}
context = {
'foods': foods,
'info': info,
}
return render(request, 'greeting.html', context)
왼쪽은 key, 오른쪽은 value(배열이나 딕셔너리 변수들)을 사용한 것이다. context에서는 왼쪽의 key의 값을 사용하는 것이다.
이 경우 info 안의 name을 사용하고 싶다면
# templates/greeting.html
...
<h1>안녕하세요. 저는 {{ info.name }} 입니다.</h1>
...
배열을 사용하고 싶다면 다음과 같이 한다.
<!-- templates/greeting.html -->
...
<p>안녕하세요. 저는 {{ info.name }} 입니다.</p>
<p>제가 좋아하는 음식들은 {{ foods }} 입니다.</p>
<p>제가 가장 좋아하는 음식은 {{ foods.0 }} 입니다.</p>
리스트의 0번 인덱스의 값을 가져올 때는 array.0 처럼 array.idx
방식으로 사용한다.
Filters
- 표시한 변수를 원하는 형식으로 수정할 때 사용
- 60개의 built-in template filters 제공
- chained 가능
- 일부 필터는 인자를 받기도 한다.
{{ variables|filter }}
{{ name|lower }}
{{ variable|truncatewords:30 }}
예시
# view.py
import random
def dinner(request):
foods = ['족발', '햄버거', '치킨', '초밥']
pick = random.choice(foods)
context = {
'foods': foods,
'pick': pick,
}
return render(request, 'dinner.html', context)
<!-- templates/dinner.html -->
<h1>오늘 저녁은 {{ pick }}이다!!</h1>
<p>{{ pick }}은 {{ pick|length }}글자</p>
<p>{{ foods|join:", "}}</p>
Tags
- 변수보다 복잡한 일들을 수행할 때 사용
- 출력 텍스트를 만들거나, 반복 또는 논리를 수행하여 제어 흐름 제작
- 일부 태그는 시작과 종료 태그 필요
- 24개의 built-in template tags 제공
{% tag %}
{% for %}{% endfor %}
Comments
- Django template에서 라인의 주석을 표현하기 위해 사용
<!-- 한 줄 주석 -->
{# ... #}
<!-- 여러 줄 주석 -->
{% comment %}
<p>여러 줄</p>
<p>주석</p>
<p>주석</p>
{% endcomment %}
템플릿 상속
- 템플릿 상속은 기본적으로 코드의 재사용성에 초점을 맞춤
- 템플릿 상속을 사용하면 사이트의 모든 공통 요소를 포함
- 하위 템플릿이 재정의(override)할 수 있는 블럭 정의
- 기본 skeleton 템플릿(base.html)을 제작 가능
block tag
{% block content %}
{% endblock %}
- 하위 템플릿에서 재지정(override)할 수 있는 블럭을 정의
- 즉, 하위 템플릿이 채울 수 있는 공간
- 부모 템플릿에 block 태그로 공간을 비워두고 하위 템플릿에서 그 공간을 채운다.
BASE_DIR
- django는 app의 templates 내의 html 파일만 읽는다.
- 그렇다고 templates 폴더 내에 base.html 파일을 두기에는 상위 파일같지 않다.
- 상위 폴더는 독립적인 느낌을 주면 좋겠다.
“Django야 나 추가 템플릿 경로 등록할래!”
프로젝트, App과 같은 수준, 즉 최상위 폴더에 templates 폴더 만들고 이 경로를 pjt의 settings.py에 등록!!
# settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
위의 코드에 DIRS의 빈 리스트 값에 아래처럼 채워넣는다.
'DIRS': [BASE_DIR / 'templates', ],
BASE_DIR은 뭐길래 알아서 정의가 되고 오류가 생기지 않을까?
- settings.py 파일의 위쪽에 선언되어 있다.
- 장고 프로젝트를 가지고 있는 최상단 폴더 의미
- Python의 객체지향적인 파일 경로 : 운영체제의 영향을 받지 않는다!
base.html
상위 html 파일, 즉 상속에서의 부모 템플릿이 되는 base.html이다.
<!-- firstpjt/templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" cntent="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous"
/>
<title>Document</title>
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
<a href="#" class="navbar-brand">Navbar</a>
</nav>
{% block content %} ⭐
{% endblock content %} ⭐
</body>
</html>
- Navbar를 위해 상위 html 템플릿에 Nav와 관련된 코드를 넣어준다.
- block tag를 이용해 하위 템플릿에서 이를 extends하면 이 곳에 하위 템플릿의 html 코드를 넣어준다.
- block tag에 block ~~~에는 content 등 여러 block에서 이들을 구분하는 표시를 반드시 해준다.
- endblock tag에는 넣어도 되고, 안 넣어도 된다. 선택이다.
extends tag
{% extends 'base.html' %}
- 자식(하위) 템플릿이 부모 템플릿을 확장, 즉 상속한다는 것을 의미
주의📢 반드시 템플릿 최상단에 작성
하위 템플릿 예시 : greeting.html
component처럼 사용하는 하위 템플릿
<!-- greeting.html -->
{% extends 'base.html' %}
{% block content %}
<p>안녕하세요. 저는 {{ info.name }} 입니다.</p>
<p>제가 좋아하는 음식들은 {{ foods }} 입니다.</p>
<p>제가 가장 좋아하는 음식은 {{ foods.0 }} 입니다.</p>
{% endblock content %}
include
- 템플릿을 로드하고 현재 페이지로 렌더링
- 템플릿 내에 다른 템플릿을 포함(include)
<!-- templates/_nav.html -->
<nav class="navbar navbar-dark bg-dark">
<a href="#" class="navbar-brand">Navbar</a>
</nav>
- templates/ 디렉토리에 _nav.html 생성
- 이후 base.html에 있던
<nav>...</nav>
잘라내기 후 붙여넣기 - 해당 위치에 include tag로 _nav.html 삽입
<!-- firstpjt/templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" cntent="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous"
/>
<title>Document</title>
</head>
<body>
{% include '_nav.html' %} ⭐
{% block content %}
{% endblock content %}
</body>
</html>
- _(언더바)는 include되는 템플릿임을 의미
- 하지만 특수한 기능이나 규칙은 포함하지 않는다.
Template 설계 철학
표현과 로직(view)을 분리
- 표현을 제어하는 도구
- 표현에 관련된 로직일 뿐
- 템플릿 시스템은 기본 목표를 넘어서는 기능을 지원하지 말아야 한다.
중복을 배제
- 대부분 header, footer, navbar 같은 사이트 공통 디자인을 갖는다.
- 이러한 요소들의 중복 코드를 없애야 한다.
- 이것이 상속의 기초가 되는 철학
댓글남기기