템플릿(Template)
템플릿이란, 장고 뷰에서 웹사이트를 반환할 때, 웹사이트 정보를 하드코딩으로 생성하지 않고, 다르게 관리할 수 있게 해주는 장고의 기능이다.
사이트 생성을 도와주는 것이기에, 장고를 DRF 등의 프레임워크를 통해 REST API를 사용하는 API 서버용으로 사용한다면 이용할 일이 없는 기능이다.
이때 템플릿은 .html의 파일로 생성을 하며, 내부의 파일은 완전한 html은 아니고, 장고의 템플릿 태그(template tag)를 문법이 추가된 형태이다.
템플릿 파일 작성 위치
그렇다면 템플릿은 어느 위치에 정의할까? 이것에는 크게 2가지 방법이 보통 사용된다. 첫 번째는 각 앱의 templates/ 폴더를 정의해 각 앱별로 모아두거나, 프로젝트의 매인앱에 templates/ 폴더를 생성하여 하위에 앱별, 또는 일정한 기준으로 분류를 하는 것이다.
settings.py를 보면 다음과 같은 코드가 존재한다.
# ./django_basic/settings.py
TEMPLATES = [
{
...
"APP_DIRS": True,
},
]
이때 APP_DIRS를 True로 해두면 장고가 settings.py의 INSTALLED_APPS에 정의된 앱들의 하위 tempaltes/ 폴더를 자동으로 탐색하여 템플릿 파일을 인식한다.
해당 글에서는 각 앱마다 templates/ 폴더를 정의하겠다. 이때 템플릿 파일들을 바로 templates/ 폴더에 생성하는 것은 좋지 않은데, 이것은 바로 여러 앱에서 중복된 파일명을 가진 템플릿이 있을 경우에 장고는 이를 구별하지 못하기 때문이다. 그렇기에 템플릿에 대하여 namespace를 잘 정해주는 것이 좋다. namespace를 통하여 구분해 주기 위해서는 바로 templates/ 폴더에 템플릿 파일을 생성하는 것이 아닌, templates/ 폴더 하위에 앱의 이름과 같은 폴더를 하나 더 생성한 후 그 안에 넣어주거나 하면 된다.
템플릿 파일 작성
books앱에 템플릿 파일을 생성해 볼 텐데, 이때 바로 books/templates/index.html 에 생성하는 것이 아닌, books/templates/books/index.html 처럼 생성하겠다.
{# books/templates/books/index.html #}
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
<a href="/books/{{ book.id }}/">{{book.title}} - {{ book.author.name }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>책 데이터가 없습니다</p>
{% endif %}
보통의 html 파일과 달리 {% %}와 {{ }}등 처음 보는 문법들이 여럿 보인다. 우선은 넘어가고, 이렇게 정의한 템플릿을 어떻게 뷰에서 사용하는지 보자.
템플릿 파일 뷰에 연결
# books/views.py
from django.http import HttpResponse
from books.models import Book
from django.template import loader
def books(request):
books = Book.objects.all()
context = {
"book_list": books,
}
template = loader.get_template("books/index.html")
return HttpResponse(template.render(context, request))
template의 loader.get_template()을 이용하여 템플릿을 가져오고, 이에 context와 request를 넣어주며 render 시키고 있다. 하지만 사실 이러한 방식은 자주 사용되는 방식은 아니고, 실제로는 render()을 이용한다.
# books/views.py
from django.http import HttpResponse
from books.models import Book
from django.shortcuts import render
def books(request):
books = Book.objects.all()
context = {
"book_list": books,
}
return render(request, "books/index.html", context)
위와 같이 django.shorcuts에서 제공하는 render()를 사용하는 것이 깔끔하다.
템플릿 문법
그럼 다시 템플릿으로 돌아와 템플릿 파일을 작성하는 방법을 알아보겠다. 템플릿은 기본적으로 html을 기반으로 하고 있는데, 이때 여기서 장고의 기능으로 조건문, 반복문 등의 제어문을 사용할 수 있고, 템플릿에 context를 전달하여 데이터를 편하게 전달하고 표시할 수 있다.
이때 문법에서 제어문은 {% %} 태그 안에 들어가고, context로 전달한 데이터들은 {{ }} 태그 안에 넣어 사용할 수 있다.
{# books/templates/books/index.html #}
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
<a href="/books/{{ book.id }}/">{{book.title}}
-
{{ book.author.name }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>책 데이터가 없습니다</p>
{% endif %}
조건문은 {% if ~ %}, {% else %}, {% endif %}로 이루어진다. 이때 조건문에는 실제 조건문처럼 ==, <= 등의 비교문을 통하여 조건을 작성할 수는 없고, 단지 bool값을 가지거나 bool값의 역할을 할 수 있는 데이터를 context로 받아서 사용하는 것이다. 즉, 기능이 매우 한정적이어서 실제 구체적인 조건문은 뷰에서 미리 처리를 해주어야 한다.
HTML파일을 기반으로 하기에 {% endif %}와 같이 제어문을 종료해 주는 문법을 반드시 작성해주어야 한다.
반복문은 {% for 개체명 in 개체리스트명 %}으로 사용하며 장고의 쿼리셋 등을 바로 전달할 수도 있다.
역시나 {% endfor %}로 제어문을 잘 닫아주는 것이 중요하다.
{{ 이름 }} 으로 데이터를 불러올 수 있는데, 이때 데이터는 context로 넘긴다. 쿼리셋 등을 바로 접근할 수 있어 편리하다.
참고로 {# #}로 작성된 것은 주석이다.
하이퍼링크 하드코딩 제거 하기
{# books/templates/books/index.html #}
<a href="/books/{{ book.id }}/">{{book.title}} - {{ book.author.name }}</a>
위의 예시에서 a href링크가 하드코딩돼 있는 것을 확인할 수 있다. 이러면 이후에 url.py에 지정해 둔 링크를 변경할 때 일일이 템플릿을 변경해 주어야 한다. 이를 방지하기 위해서 장고에서는 다음과 같은 기능을 제공한다.
{# books/templates/books/index.html #}
<a href="{% url 'book_detail' book.id %}">{{book.title}} - {{ book.author.name }}</a>
위와 같이 url 태그를 이용하여 이동할 링크의 이름을 지정하여 url이 변경되어도 대응할 수 있다. 이때 book.id처럼 파라미터를 넘겨줄 수도 있다. 그렇다면 이 book_detail이라는 이름은 어디서 난 걸까? 이는 이전에 작성하였던 urls.py에서 확인할 수 있다.
# books/urls.py
from django.urls import path
from books import views
urlpatterns = [
path("", views.books, name="books"),
path("<int:book_id>/", views.book_detail, name="book_detail"),
path("create/", views.create_book, name="create_book"),
]
보면 이전에 name= 으로 이름을 지정해 주었는데, 이렇게 지정된 이름은 이렇게 템플릿등에서 사용한다.
URL name namespace
번외로, 우리가 템플릿 파일에 namespace를 적용해 주었듯이, URL name에도 네임스페이스를 지정해 줄 수 있다. 방법은 다음과 같다.
우선 urls.py에 app_name을 지정해 준다.
# books/urls.py
from django.urls import path
from books import views
app_name = "books"
urlpatterns = [
...
]
그리고 템플릿을 수정해 준다.
{# books/templates/books/index.html #}
<a href="{% url 'books:book_detail' book.id %}">{{book.title}} - {{ book.author.name }}</a>
여기까지 진행했을 때의 파일 구성: Github
'파이썬 (Python) > 장고 (Django)' 카테고리의 다른 글
Django에 redis 캐싱 적용하기 (0) | 2024.02.09 |
---|---|
장고 필드의 null, blank에 대한 정리 (0) | 2023.08.18 |
dj-rest-auth 소셜 로그인(OAuth)에 대하여 (0) | 2023.07.27 |
[Django Basic] 4. View, views.py (0) | 2023.07.27 |
DRF OAuth 라이브러리 비교 (0) | 2023.07.24 |