Django - Template System

템플릿 시스템

템플릿에서는 로직을 표현하는 것이 아니라 사용자에게 어떻게 보여줄지에 대한 룩앤필을 표현한다.
Django 의 템플릿 시스템은 템플릿 코드를 해석하여 HTML, XML, CSV 등의 단순한 텍스트 파일로 결과물을 만들어 준다.

템플릿 변수

{{ variable }}
  • 변수명은 문자, 숫자, 언더바(_)를 사용한다.
  • 변수의 속성에 접근할 수 있는 도트(.) 표현식도 가능
    • foo.bar 라는 변수가 있다면
      • foo가 사전타입이면, foo['bar']로 해석
      • 다음으로는 foo의 속성을 찾아서 bar 라는 속성이 있으면, foo.bar 로 해석
      • 마지막으로 foo가 리스트이면, foo[bar]로 해석
  • 정의가 되어 있지 않은 변수는 기본적으로 빈 문자열('')로 인식
    • 이러한 기본 값을 변경하려면 settings.py 파일에서 TEMPLATE_STRING_IF_INVALID 속성을 지정한다.

템플릿 필터

템플릿 변수에 필터를 적용하여 변수의 출력 결과를 변경할 수 있다.

{{ name|lower }}  // name 변수값의 모든 문자를 소문자로 바꿔주는 필터
{{ text|escape|linebreaks }}
// 필터를 체인으로 연결하는 것도 가능하다.
// 특수 문자를 이스케이프 한 후, 결과 스트링에 <p> 태그를 붙여준다.
{{ bio|truncatewords:30 }}    // bio 변수값 중 앞 30개 단어만 보여주고, 줄 바꿈 문자는 없앤다.
{{ list|join:" !! " }}    // ['a', 'b', 'c'] => "a !! b !! c"
{{ value|default:"nothing" }}    // value가 False 이거나 없는 경우, "nothing"
{{ value|length }}    // value 변수값의 길이 반환
{{ value|striptags }}    // value 값에서 html 태그를 없앤다.(100% 보장 X)
{{ value|pluralize }}    // value 값이 1이 아니면 복수 접미사 's'를 붙인다.
{{ value|pluralize:"es" }}
{{ value|pluralize:"y, ies" }}
{{ value|add:"2" }}       // 변수값에 인자를 더한다.
{{ first|add:second }}

템플릿 태그

{% tag %} 형태, 텍스트 결과물을 만들거나, 템플릿 로직을 제어하기도 하며, 외부 파일을 로딩하기도 한다.

{% for %} 태그
<ul>  
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>  
  • for 태그에 사용되는 변수들
    • forloop.counter: 현재까지 루프를 실행한 루프 카운트(1부터)
    • forloop.counter0: 현재까지 루프를 실행한 루프 카운트(0부터)
    • forloop.revcounter: 루프 끝에서 현재가 몇 번째인지 카운트(1부터)
    • forloop.revcounter0: 루프 끝에서 현재가 몇 번째인지 카운트(0부터)
    • forloop.first: 루프에서 첫 번째 실행이면 True 반환
    • forloop.last: 루프에서 마지막 실행이면 True 반환
    • forloop.parentloop: 중첩된 루프에서 현재 루프의 상위 루프를 의미함
{% if %} 태그
{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
    Athletes should be out of the locker room soon!
{% else %}
    No athletes.
{% endif %}

어렵지 않으니 설명은 패스~!
다음과 같이 {% if %} 태그에 필터와 연산자를 사용할 수 있다.

{% if athlete_list|length > 1 %}

그리고 다음과 같은 boolean 연산자를 사용할 수 있다.

and, or, not, and not, ==, !=, <, >, <=, >=, in, not in  
{% csrf_token %} 태그
<form action="." method="post">  
{% csrf_token %}
  • 태그 첫 줄 다음에 위치
  • CSRF 토큰 값이 유출될 수 있으므로, 외부 URL 로 보내는 에는 사용하지 않도록 한다.
{% url %} 태그
{% url 'namespace:view-name' arg1 arg2 %}
  • 소스에 URL을 하드 코딩하는 것을 방지한다.
{% with %} 태그
{% with total=business.employees.count %}
    {{ total }} people works at business
{% endwith %}
  • 특정 값을 변수에 저장해 둔다.
  • 변수는 with~endwith 내에서만 유효하다.
{% load %} 태그
{% load somelibrary package.otherlibrary %}
  • 사용자 정의 태그 및 필터를 로딩한다.
  • 위 예제는 somelibrary.py 파일 및 package/otherlibrary.py 파일에 정의된 사용자 정의 태그 및 필터를 로딩한다.

템플릿 주석

한 줄 주석
{# greeting #}hello
{# {% if foo %}bar{% else %} #}
여러 줄 주석
{# comment "Optional note" #}
<p>Commented out thext here</p>  
{# endcomment #}

HTML 이스케이프

Django는 기본적으로 HTML에 사용되는 예약 문자들을 아래와 같이 예약 의미를 제거한 문자로 변경해준다.

< (less than) 문자는 &lt;  
> (greater than) 문자는 &gt;
' (single quote) 문자는 &#39;  
" (double quote) 문자는 &quot;
& (ampersand) 문자는 &amp;

Django 에서 HTML 이스케이프를 방지하는 방법은 두가지가 존재한다.

safe 필터
This will not be escaped: {{ data|safe }}  
{% autoescape %} 태그
{% autoescape off %}
Hello {{ name }}  
{% endautoescape %}

템플릿 상속

템플릿 코드의 재사용과 일관성 있는 사이트의 룩앤필을 구성할 수 있게 해준다.

  • 부모 템플릿은 뼈대를 만들고, {% block %} 태그를 통해 상속해줄 부분을 지정한다.
  • 자식 템플릿은 부모 템플릿의 뼈대를 그대로 사용하고 {% block %} 부분만 채워준다.
부모 템플릿
<!DOCTYPE html>  
<html lang="en">  
  <head>
    <link rel="stylesheets" href="style.css" />
    <title>{% block title %}My amazing site{% endblock %}</title>
  </head>
  <body>
    <div id="sidebar">
      {% block sidebar %}
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/blog">Blog</a></li>
      </ul>
      {% endblock %}
    </div>

    <div id="content">
      {% block content %}{% endblock %}
    </div>
  <body>
</html>  
자식 템플릿
{% extends "polls/base.html" %}

{% block title %}My amazing blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
  <h2>{{ entry.title }}</h2>
  <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

위의 템플릿이 브라우저에 렌더링된 결과는 아래와 같다.

<!DOCTYPE html>  
<html lang="en">  
  <head>
    <link rel="stylesheets" href="style.css" />
    <title>My amazing blog</title>
  </head>
  <body>
    <div id="sidebar">

      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/blog">Blog</a></li>
      </ul>

    </div>

    <div id="content">


  <h2>Entry one</h2>
  <p>This is my first entry.</p>

  <h2>Entry two</h2>
  <p>This is my second entry.</p>


    </div>
  <body>
</html>  
템플릿 상속 정의시 유의할 사항
  • {% extends %} 태그는 사용하는 태그 중 가장 먼저 나와야 한다.
  • 템플릿의 공통 사항을 가능한 많이 뽑아서 1단계 부모 템플릿에 {% block %} 태그가 많아지도록 한다.
  • 부모 템플릿의 {% block %} 태그를 그대로 자식 템플릿에서 사용하려면 {{ block.super }} 변수를 사용한다.
  • 가독성을 높이기 위해 {% endblock content %} 처럼 블록명을 기입할 수 있다.