1. Django 템플릿 사용의 두 가지 방법
# 방법 1: render() 함수 사용
return render(request, 'time.html', context={'current_date': str(now), 'title': 'Hello Django'})
# 방법 2: 수동 템플릿 렌더링 (페이지 정적화에 유용)
from django.shortcuts import render, HttpResponse
from django.template import Template, Context
import datetime
now = datetime.datetime.now()
from myproject import settings
import os
file_path = os.path.join(settings.BASE_DIR, 'templates', 'time.html')
file_content = open(file_path, 'r', encoding='utf-8').read()
template = Template(file_content)
context = Context({'current_date': str(now), 'title': 'Hello Django'})
rendered_html = template.render(context) # 렌더링된 문자열
# 렌더링 결과를 파일로 저장하여 정적 파일로 제공 가능 (동적/정적 전환 로직 구현)
return HttpResponse(rendered_html)
2. 템플릿 문법: 변수
# views.py
def index(request):
number = 10
text = 'Hello World'
flag = True
items = [1, 2, 43]
info = {'name': 'Alice', 'age': 25}
def my_function():
return 'Function result here'
class User():
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
user = User('Alice')
# locals()를 사용하여 모든 지역 변수를 템플릿 컨텍스트로 전달
return render(request, 'index.html', locals())
# index.html
<html>
<head>
<meta charset="UTF-8">
<title>{{ text }}</title>
</head>
<body>
<h1>템플릿 변수 문법</h1>
<p>숫자: {{ number }}</p>
<p>문자열: {{ text }}</p>
<p>불리언: {{ flag }}</p>
<p>리스트: {{ items }}</p>
<p>딕셔너리: {{ info }}</p>
<p>함수: {{ my_function }}</p>
<p>객체: {{ user }}</p>
</body>
</html>
3. 템플릿 문법: 점(.) 연산자를 통한 깊은 조회
# views.py
def index(request):
number = 10
text = 'Hello World'
flag = True
items = [1, 2, 43, {'name': 'Bob'}]
info = {'name': 'Alice', 'age': 25}
def my_function():
return 'Function result'
class User():
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
user = User('Alice')
raw_link = '<a href="https://example.com">Click Me</a>'
safe_link = mark_safe(raw_link)
raw_input = '<p>Username: <input type="text" name="user"></p>'
safe_input = mark_safe(raw_input)
raw_script = '''
<script>
alert('XSS test');
</script>
'''
safe_script = mark_safe(raw_script)
return render(request, 'index.html', locals())
# index.html
<h2>점(.) 연산자를 통한 깊은 조회</h2>
<p>리스트 첫 번째 요소: {{ items.1 }}</p>
<p>딕셔너리의 name 값: {{ info.name }}</p>
<p>리스트 네 번째 요소의 name 값: {{ items.3.name }}</p>
<p>함수 실행: {{ my_function }}</p>
<p>클래스 메서드 호출: {{ user.get_name }}</p>
<p>클래스 속성 접근: {{ user.name }}</p>
<hr>
<p>안전하지 않은 링크 문자열: {{ raw_link }}</p>
<p>안전한 링크 (HTML 렌더링): {{ safe_link }}</p>
<p>안전하지 않은 input: {{ raw_input }}</p>
<p>안전한 input: {{ safe_input }}</p>
<p>안전하지 않은 스크립트: {{ raw_script }}</p>
{{ safe_script }}
4. 내장 필터
1. default
# 변수가 false이거나 비어있으면 기본값 사용
{{ value|default:"nothing" }}
2. length
# 문자열 또는 리스트의 길이 반환
{{ value|length }}
3. filesizeformat
# 파일 크기를 사람이 읽기 쉬운 형식으로 변환
{{ value|filesizeformat }}
4. date
# 날짜/시간 형식 변환
{{ value|date:"Y-m-d" }}
5. slice
# 문자열 슬라이싱
{{ value|slice:"2:-1" }}
6. truncatechars
# 문자열을 지정된 문자 수로 자르고 '...' 추가
{{ value|truncatechars:9 }}
7. safe
# HTML 태그 자동 이스케이프 방지
value="<a href=''>Click</a>"
{{ value|safe }}
실제 사용 예시
<p>기본값 필터: {{ number|default:'No value' }}</p>
<p>길이 필터: {{ items|length }}</p>
<p>길이 필터 (딕셔너리): {{ info|length }}</p>
<p>파일 크기 포맷: {{ number|filesizeformat }}</p>
<p>슬라이스 필터: {{ text|slice:"7:11" }}</p>
<p>문자 자르기 (truncatechars): {{ text|truncatechars:'30' }}</p>
<p>단어 자르기 (truncatewords): {{ text|truncatewords:'2' }}</p>
<p>날짜 포맷: {{ current_time|date:'Y-m-d H:i:s' }}</p>
<p>안전한 HTML 출력: {{ raw_link|safe }}</p>
{# add: 값 더하기 #}
<p>{{ "10"|add:"-2" }}</p>
{# upper/lower: 대소문자 변환 #}
<p>{{ text|upper }}</p>
<p>{{ 'EXAMPLE'|lower }}</p>
5. 템플릿 태그
for 루프 활용
{# forloop 속성들 #}
{% for item in items %}
{{ forloop.counter }} {# 1부터 시작하는 인덱스 #}
{{ forloop.counter0 }} {# 0부터 시작하는 인덱스 #}
{{ forloop.revcounter }} {# 1부터 시작하는 역순 인덱스 #}
{{ forloop.revcounter0 }} {# 0부터 시작하는 역순 인덱스 #}
{{ forloop.first }} {# 첫 번째 반복인지 확인 #}
{{ forloop.last }} {# 마지막 반복인지 확인 #}
{% endfor %}
{# 중첩 루프에서 parentloop 사용 #}
{% for outer_list in data %}
{% for item in outer_list %}
{{ forloop.parentloop.counter }}
{{ forloop.counter }}
{% endfor %}
{% endfor %}
for ... empty 태그
{% for person in person_list %}
<p>{{ person.name }}</p>
{% empty %}
<p>No persons found.</p>
{% endfor %}
if 태그
{% if score > 100 or score < 0 %}
<p>Invalid score</p>
{% elif score > 80 and score < 100 %}
<p>Excellent</p>
{% else %}
<p>Average</p>
{% endif %}
{# 지원 연산자: and, or, ==, >, <, !=, <=, >=, in, not in, is, is not #}
{# 주의: 연속 비교는 지원하지 않음 (예: a > b > c) #}
with 태그
{# 복잡한 변수를 간단한 이름으로 캐싱 #}
{% with total=company.employees.count %}
{{ total }} {# with 블록 내에서만 사용 가능 #}
{% endwith %}
{% with company.employees.count as total %}
{{ total }}
{% endwith %}
csrf_token 태그
{# POST 폼에서 CSRF 보호를 위해 필수 #}
<form method="post">
{% csrf_token %}
<input type="text" name="data">
<button type="submit">Submit</button>
</form>
템플릿 포함과 상속
{# 템플릿 포함 (include) #}
{% include 'navbar.html' %}
{% include 'footer.html' %}
{# 템플릿 상속 (extends) #}
{% extends 'base.html' %}
{% block content %}
{{ block.super }} {# 부모 블록 내용 유지 #}
<h2>Sub page content here</h2>
{% endblock %}
사용자 정의 필터와 태그
# 1. 앱 폴더에 templatetags 패키지 생성
# 2. templatetags 폴더에 Python 파일 생성 (예: custom_tags.py)
# 3. settings.py의 INSTALLED_APPS에 앱 등록
# custom_tags.py
from django import template
register = template.Library()
# 사용자 정의 필터
@register.filter
def custom_filter(value, arg=''):
return value + ' ' + arg
# 사용자 정의 태그
@register.simple_tag
def custom_tag(v1, v2, v3):
return f'{v1} + {v2} + {v3}'
# inclusion_tag
@register.inclusion_tag('list_component.html')
def render_list(count):
data = ['Item {}'.format(i) for i in range(count)]
return {'data': data}
# HTML 템플릿에서 사용
{% load custom_tags %}
{{ value|custom_filter:'argument' }}
{% custom_tag 'A' 'B' 'C' %}
{% render_list 5 %}
inclusion_tag 상세 사용법
# custom_tags.py
@register.inclusion_tag('menu.html')
def sidebar(menu_count):
menu_items = {i: 'Page {}'.format(i) for i in range(menu_count)}
return {'menu_items': menu_items}
# menu.html
{% for key, value in menu_items.items %}
<p>Key: {{ key }}, Value: {{ value }}</p>
{% endfor %}
# 사용 템플릿
{% load custom_tags %}
<div class="sidebar">
{% sidebar 10 %}
</div>