본문 바로가기
Django

[Django] 템플릿 코드

by dio-han 2022. 1. 5.

 

1. 템플릿 변수

 

{{ variable }}

 

템플릿 시스템은 변수를 평가해서 변수값으로 출력해준다. 변수명은 일반 프로그래밍의 변수명처럼 문자, 숫자, 밑줄을 사용하여

이름을 정의한다. 또한 변수의 속성에 접근할 수도 있는 도트(.) 표현식도 가능하다.

 

장고의 템플릿 시스템에서 도트(.)는 파이썬 언어와는 조금 다르다. 템플릿 문법에서 도트(.)를 만나면 장고는 다음 순서로 찾기

(lookup)를 시도한다. 예를 들어, foo.bar라는 템플릿 변수가 있다면 다음과 같이 해석한다.

 

- foo가 사전 타입인지 확인, 그렇다면 foo['bar'] 로 해석한다.

- 그 다음은 foo의 속성을 찾는다. bar라는 속성이 있으면 foo.bar로 해석한다.

- 그 다음은 foo가 리스트인지 확인한다. 그렇다면 foo[bar]로 해석한다.

 

템플릿 시스템은 정의가 되어 있지 않은 변수를 사용하는 경우, 빈 문자열(' ')로 채워주며, 이 값을 변경하려면 settings.py 파일에

다음과 같이 속성을 지정해주면 된다. 디폴트는 빈 문자열

 

TEMPLATE_STRING_IF_INVALID

 

2. 템플릿 필터

필터란 일반적인 용어로 어떤 객체나 처리 결과에 추가적으로 명령을 적용하여 해당 명령에 맞게 최종 결과를 변경하는 것을 말한다.

장고의 템플릿 문법에서도 템플릿 변수에 필터를 적용하여 변수의 출력 결과를 변경할 수 있다.

 

필터는 아래처럼 파이프( | ) 문자를 사용한다. name 변수값의 모든 문자를 소문자로 바꿔주는 필터

 

{{ name|lower }}

 

필터를 체인으로 연결할 수도 있다. text 변수값 중에서 특수 문자를 이스케이프해주고 (escape), 그 결과 스트링에 HTML <p>

태그를 붙여준다.(linebreaks)

 

{{ text|escape|linebreaks  }}

 

몇 가지의 필터는 인자를 가질 수 있다. 다음은 bio 변수값 중에서 앞에 30개의 단어만 보여주고, 줄 바꿈 문자는 모두없애준다.

 

{{ bio}truncatewords:30 }}

 

필터의 인자에 빈칸이 있는 경우는 따옴표로 묶어준다. 만일 list가 ['a', 'b', 'c'] 라면 결과는 "a // b // c"가 된다.

 

{{ list|join:" // " }}

 

value 변수값이 False이거나 없는 경우, "nothing"으로 보여준다.

 

{{ value}default:"nothing" }}

 

value 변수값의 길이를 반환한다. value가 스트링이나 리스트인 경우도 가능, 예를 들어 value가 ['a', 'b', 'c']이면 결과는 3

 

{{ value | length }}

 

 value 변수값에서 HTML 태그를 모두 없애준다.

 

{{ value | striptags }}

 

접미사 필터

 

{{ value|pluralize }}

 

value 변수값이 1이 아니면 복수 접미사 s를 붙여준다. 다른 복수 접미사 es 또는 ies를 붙일 때는 필터에 인자를 사용한다.

 

{{ value|pluralize:"es" }} 또는 {{ value|pluralize:"ies" }}

 

다음은 더하기 필터, 만일 value 변수값이 4라면, 아래 표현식의 최종 결과는 6이 된다. 데이터 타입에 따라 결과가 달라진다.

 

{{ value|add:"2" }}

 

처음에는 value 변수값과 add 필터의 인자가 모두 integer 타입이라고 간주하고 덧셈을 시도한다. 이 시도가 실패하면 타입이

허용하는 문법에 따라 더하기를 시도한다. 이 시도는 성공할 수도 있고 실패할 수도 있는데, 실패하는 경우는 빈 문자열을 반환

 

 

3. 템플릿 태그

 

템플릿 태그는 {% tag %} 형식을 가지며, 템플릿 변수나 필터에 비해 좀 더 복잡한 편이다. 어떤 태그는 시작 태그와 끝 태그 둘 다

있어야 한다. 텍스트 결과물을 만들기도 하고, 템플릿 로직을 제어하기도 하며, 외부 파일을 템플릿 내로 로딩하기도 한다.

 

템플릿 태그는 {% for %} 태그와 {% if %} 태그를 가장 많이 사용한다.

 

{% for %} 태그

 

{% for %} 태그를 사용하면 리스트에 담겨 있는 항목들을 순회하면서 출력할 수 있다.

&nbsp;

위 예시는 운동 선수 리스트에 들어있는 항목을 순회하면서 각 운동 선수의 이름(athelete.name)을 보여주는 문장이다. 또한

{% for %} 태그를 사용하여 로프를 돌 때 사용할 수 있는 여러 가지의 변수를 제공하고 있다.

{% if %} 태그

 

{% if %} 태그이다. 변수를 평가하여 True이면 바로 아래의 문장이 표시된다.

만일 athlete_list 변수가 True이면 운동 선수 숫자가 표시될 것이고, athlete_in_locker_room_list 변수가 True이면 그 아래

문장이 화면에 나타날 것이다. 또한, 두 조건 모두 아니라면 No Athletes.라는 문장이 나타날 것이다.

 

{% if %} 태그는 다음과 같은 문법도 가능하다. 즉, {% if %} 태그에 필터와 연산자를 사용할 수 있다는 것이다. 

주의할 점은 대부분의 필터가 스트링을 반환하므로 산술 연산이 안 되는데, length 필터는 예외적으로 가능하다.

 

또한, {% if %} 태그에는 아래와 같은 불린 연산자를 사용할 수 있다는 점 알아두기

 

 

{% csrf_token %} 태그

 

POST 방식의 <form> 을 사용하는 템플릿 코드에서는 CSRF(Cross Site Request Forgery) 공격을 방지하기 위하여

{% csrf_token %} 태그를 사용해야 한다. 폼 데이터에는 악의적인 스크립트 문장이 들어있을 수도 있기 때문이다.

위치는 <form> 엘리먼트의 첫 줄 다음에 넣어주면 된다. 이 태그를 사용하면 장고는 내부적으로 CSRF 토큰값의 유효성을

검증한다. 만일 CSRF 토큰 값 검증에 실패하면 사용자에게 403 에러를 보여준다. 외부 URL로 보내는 <form>에는 

토큰값이 유출될 수 있으므로 사용하지 않도록 한다.

 

 

{% url %} 태그

 

{% url %} 태그도 자주 사용한다. 

 

이 태그의 주 목적은 소스에 URL을 하드코딩하는 것을 방지하기 위한 것이다. 만일 이 태그를 사용하지 않는다면 

이렇게 하드코딩해야 한다.

 

태그의 사용 형식

 

{% with %} 태그

 

{% with %} 태그는 특정 값을 변수에 저장해두는 기능을 한다.

위 문장에서 total 변수의 유혀 범위는 with 구문 내 이다. 이 태그는 데이터베이스를 조회하는 것처럼 부하가 큰 동작의 결과를

저장해 둠으로써, 다시 동일한 동작이 필요한 경우에는 저장해 둔 결과를 활용하여 부하를 줄이기 위한 태그이다.

 

{% load %} 태그

 

{% load %} 태그는 사용자 정의 태그 및 필터를 로딩해준다.

 

태그 및 필터는 장고 에서 기본적으로 제공하는 것 외에도, 개발자가 필요에 따라 스스로 정의하여 사용할 수 있다.

이런 것을 사용자 정의 태그, 사용자 정의 필터라고 한다. 사용자 정의 태그 및 필터를 사용하기 위해서는 사용하기 전에

로딩을 먼저 해줘야 한다.

 

앞의 문장은 somelibrary.py 파일 및 package/ohterlibrary.py 파일에 정의된 사용자 정의 태그 및 필터를 로딩해준다.

 

 

4. 템플릿 주석

 

템플릿 코드에서도 주석문을 사용할 수 있다. 템플릿에 주석문을 사용하는 방법은 2가지가 있다.

 

첫 번째 한 줄 주석문

두 번째 여러 줄의 주석문

{% comment %} 태그는 중첩해서 사용할 수 없다.

 

 

5. HTML 이스케이프

템플릿 코드를 렌더링 하여 HTML 텍스트를 만들 때, 주의해야 할 사항이 있다. 만일 템플릿 변수에 HTML의 태그가 들어있는 경우,

있는 그대로 렌더링하면 원하지 않는 결과가 나올 수도 있다.

 

name = "<b>username"

 

템플릿 코드를 사용하면

 

Hello, {{ name }}

 

결과

 

Hello, <b>username

 

이 결과는 웹 브라우저에 표시될 때 <b> 태그 이후의 문장을 모두 볼드체로 바꿔버리기 때문에, 당초 원했던 결과와 다르게 나타난다. 이런 약점을 이용해서 XSS 공격이 이루어진다.

 

이처럼 사용자가 입력한 데이터를 그대로 렌더링하는 것은 위험할 수 있다. 그래서 장고는 앞서와 같은 결과를 방지하기 위해서

자동 이스케이프 기능을 제공하고 있다. 즉 장고는 디폴트로 HTML에 사용되는 예약 문자들을 아래처럼 예약 의미를 제거한 문자로

변경해주는 기능을 제공한다.

그러나 이와 같은 자동 HTML 이스케이프 기능을 비활성화시켜야 하는 경우도 발생한다. 예를들어, HTML 태그를 그대로 출력하고

싶은 경우나, 이스케이프 문자가 들어있는 이메일 메시지를 템플릿 파일에 출력하는 경우가 이에 해당된다.

 

장고의 자동 이스케이프 기능을 비활성화시키는 방법 2가지

 

첫 번재 safe 필터를 사용하여 자동 이스케이프를 방지하는 방법, safe 필터는 템플릿 변수에만 영향을 미친다.

 

This will not be escaped: {{ data|safe }}

 

두 번째는 {% autoescape %} 태그를 사용하여 자동 이스케이프를 방지하는 방법이다. 이 경우는 템플릿 코드에서 범위를 정하여

이스케이프를 방지할 수 있다.

 

{% autoescape off %}

Hello {{ name }}

{% endautoescape %}

 

추가적으로 필터의 인자에 사용되는 스트링 리터럴(literal)에는 자동 이스케이프 기능이 적용되지 않는다는 점을 알아두기 바란다.

 

6. 템플릿 상속

 

상속은 템플릿 문법 중에서 가장 복잡하지만, 그만큼 강력한 기능이다. 템플릿 상속을 통해서 템플릿 코드를 재사용할 수 있고,

사이트의 룩앤필을 일관성 있게 보여줄 수 있기 때문이다. 부모 템플릿은 템플릿의 뼈대를 만들어주고 {% block %} 태그를 통해

하위로 상속해줄 부분을 지정해주면, 자식 템플릿은 부모 템플릿의 뼈대는 그대로 재사용하고 {% block %} 부분만 채워주면 된다.

 

 

상속을 받는다는 의미에서 {% extends %} 태그를 사용한다.

{% block %} 태그를 모두 채울 필요는 없다. 자식 템플릿에서 채우지 않으면, 부모 템플릿의 내용을 그대로 사용한다.

 

 

이와 같이 템플릿 상속을 사용하면 템플릿 전체의 모습을 구조화할 수 있어 코드의 재사용이나 변경이 용이하고, 무엇보다도

사이트 UI의 룩앤필을 일관되게 가져갈 수 있다. 사이트 전체적으로 조화로운 룩앤필을 위하여 일반적으로 템플릿 상속을

3단계로 사용하는 것을 권장한다.

 

- 1 단계 : 사이트 전체의 룩앤필을 담고 있는 base.html을 만든다.

- 2 단계 : 사이트 하위의 섹션별 스타일을 담고 있는 base_news.html, base_sports.html 등의 템플릿을 만든다.

               물론 2단계 템플릿들은 1단계 base.html 템플릿을 상속받는다

- 3 단계 : 개별 페이지에 대한 템플릿을 만든다. 3단계 템플릿들은 2 단계 템플릿 중에서 적절한 템플릿을 상속받는다.

 

템플릿 상속을 정의할 때는 다음 사항의 유의해야 한다.

 

- {% extends %} 태그는 사용하는 태그 중에서 가장 먼저 나와야 한다.

- 템플릿의 공통 사항을 가능하면 많이 뽑아서 1단계 부모 템플릿에 {% block %} 태그가 많아질수록 좋다.

- 부모 템플릿의 {% block %} 안에 있는 내용을 그대로 사용하고 싶다면 자식 템플릿에서 {{ block.super }} 변수를 사용하면

된다. 부모 템플릿의 내용을 그대로 사용하면서 자식 템플릿에서 내용을 추가하는 경우에 사용할 수 있다.

- 가독성을 높이기 위하여 {% endblock content %} 처럼 블록명을 기입해도 된다.