템플릿(template) 언어
Django
의 템플릿 언어(template language
)는 강력함과 편리함 사이의 균형을 잡고자 설계됨.HTML
작업을 훨씬 수월하게 할 수 있음.python
변수 및 문법을 html
안에서 쓸 수 있도록 Django
에서 제공해주는 언어이기 때문에 html
과도 python
과도 조금 다름.템플릿 변수
템플릿 변수
를 사용하면 뷰에서 템플릿으로 객체를 전달 가능.{{ 변수 }}
점(.)
은 변수의 속성
에 접근할 때 사용.Django
의 view
에서 template
으로 context
를 전달할 수 있음.CBV
혹은 FBV
)에서 html
문서로 어떠한 객체를 보낼 수 있다는 것.
{{ section.title}}
view
에서section
이라는 객체를html
문서로 보냈을 것이고,- 그
section
이라는 객체 안에는title
이라는 속성을 가지고 있을 것임.
🔥 Django
에서는 장고 템플릿 변수
를 사용하여 html
문서 상에서도 어떠한 객체의 속성
들에 접근
할 수 있고, 이를 출력
할 수 있도록 지원.
{{ 변수.속성 | 필터 }}
|
)를 그은 다음 적용하고자 하는 필터를 명시.
{{ story.headline | upper }}
- 여기서,
upper
와 같은 것들이 바로템플릿 필터
upper
라고 명시하였으므로,story.headline
의 값을 대문자 형식으로 변환
🔥 위의 링크에서 30개 정도의 필터 내용 확인 가능.
{% %}
{% load static %}
와 같이 사용할 수도 있고, 위의 예제에서 볼 수 있듯이 if문
또는 for문
과 같이 흐름을 제어할 수 있도록 작성도 가능.HTML
문서는 프로그래밍 언어가 아니고 마크업 언어
이기 때문에 단지 문서를 웹에서 띄워주는 역할을 하게 됨.HTML
자체는 프로그래밍적 로직을 구현 불가if문
, for문
와 같은 템플릿 태그
를 사용한다면 프로그래밍적 로직을 구현 가능.{% extends %}
와 같이 단독으로 사용할 수 있는 템플릿 태그들도 있지만, {% if %}
처럼 뒤에 {% endif %}
템플릿 태그를 반드시 닫아주어야 하는 것들도 있음.🔥 위의 링크에서 상세 내용 확인 가능.
템플릿 코멘트
HTML
문서 상에서 코멘트
가 필요할 때 사용주석
과 비슷한 역할을 하고, 이는 Django
로 개발할 시 웹 브라우저에 의해 해석되어 출력되지 않음.Django
에서는 두 가지의 코멘트 형식을 제공.1
번 형식은 한 줄을 코멘트할 때 사용2
번은 여러 줄을 코멘트할 때 코멘트 태그 사이
에 코멘트를 작성.
- {# #}
- {% comment %}
{% endcomment %}
템플릿 상속
html
문서 중 기본 뼈대가 되는 문서
를 기본 템플릿
으로 정하고, 이는 공통의 코드이므로 다른 문서에서 기본 템플릿의 코드가 필요하면 상속하여 가져다 쓰는 것base.html
로 지정.extends
를 통해서 어떤 html
을 상속받을지를 결정해줌.html
에 있는 block``들과 대응시켜 그 안에 내용을 써주면 작성한 내용이 부모
html의
block` 안으로 들어가서 화면에 출력됨.
base.html
list.html
base.html
의 내용을 상속받아 가져다 씀.block content
과endblock content
사이의 내용을base.html
에 지정한 해당 영역에 넣어서 화면에 출력됨.
Django 공식 문서
Opentutorials.org
lks의 코딩일기
Django Template Language 실습
Model 설정
app/models.py
from django.db import models
class Attendance(models.Model):
# ChoiceField 사용법 알아두기
NONE = "NO"
ATTENDANCE = "AT"
ABSENT = "AB"
PART = "PT"
STATUS_CHOICES = [
(NONE, "미지정"),
(ATTENDANCE, "출석"),
(ABSENT, "결석"),
(PART, "일부참여"),
]
name = models.CharField(verbose_name="이름", max_length=10)
date = models.DateField(verbose_name="날짜")
status = models.CharField(
verbose_name="출석 여부", max_length=2, choices=STATUS_CHOICES, default=NONE
)
description = models.TextField(verbose_name="비고")
def __str__(self):
return f"출석부 : {self.name} ({self.date})"
class Meta:
verbose_name = "출석부"
verbose_name_plural = "출석부 목록"
View 설정
app/views.py
from django.shortcuts import redirect
from django.views.generic import TemplateView
from .models import Attendance, Question
# 전체 조회
class AttendanceView(TemplateView):
template_name = "attendance/list.html"
def get_context_data(self, *args, **kwargs):
attendance_qs = Attendance.objects.all().order_by("-date")
context = {}
context["attendance_qs"] = attendance_qs
return context
# 특정 페이지 조회
class AttendanceCreateView(TemplateView):
template_name = "attendance/enrolled.html"
def get(self, request, **kwargs):
response = super(AttendanceCreateView, self).get(self, request)
return response
def post(self, request):
name = request.POST.get("name", None)
date = request.POST.get("date", None)
status = request.POST.get("status", None)
description = request.POST.get("description", None)
Attendance.objects.create(name=name, date=date, status=status, description=description)
return redirect("attendance_list")
URL 설정
config/urls.py
이번 실습에서는
app 폴더
내에urls.py
파일을 생성해서 분리하지 않았음.
from django.contrib import admin
from django.urls import path
from app.views import index, AttendanceView, AttendanceCreateView
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path("admin/", admin.site.urls),
path("attendance/", AttendanceView.as_view(), name="attendance_list"),
path("attendance/create/", AttendanceCreateView.as_view(), name="attendance_create"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
HTML 설정
Django Template Language
사용
{% extends "base.html" %}
{% block content %}
<div class="warning hidden">
<h3>** 지난 일정은 출석 여부를 변경할 수 없습니다.</h3>
</div>
<div>
<table class="attendance-table">
<thead>
<tr>
<td>이름</td>
<td>날짜</td>
<td>출석여부</td>
<td>비고</td>
</tr>
</thead>
<tbody>
{% for attendance in attendance_qs%}
<tr>
<td class="name">{{attendance.name}}</td>
<td class="date">{{attendance.date|date:"Y.m.d"}}</td>
<td class="status">{{attendance.get_status_display}}</td>
<td class="description">{{attendance.description}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div>
<button type="button" class="button-bg-full" onclick="location.href='{% url 'attendance_create' %}'">출석체크하기</button>
</div>
{% endblock content %}
{% for attendance in attendance_qs%}
관련
attendance-qs
app/views.py
파일 내의AttendanceView
함수에서
get_context_data
함수를 통해Attendance
모델 규격에 맞춰db
에 저장된 데이터들로 만든QuerySet
-QuerySet
:Database
에서 전달받은 객체들의 모음(list
)attendance
attendance-qs
이라고 하는QuerySet
내에 있는 요소 객체
Attendance
모델에서 정의한field
를 본인 객체의 속성 데이터으로 가지고 있음.
{{attendance.name}}
관련# list.html <td class="name">{{attendance.name}}</td> <td class="date">{{attendance.date|date:"Y.m.d"}}</td> <td class="status">{{attendance.get_status_display}}</td> <td class="description">{{attendance.description}}</td>
attendance
는 위에서 설명한QuerySet
내의 요소 객체 각각을 의미.attendance.name
은 그 객체 내의 속성을 의미하며, 이는views.py
에서 생성한 각각의 변수를 뜻함.# views.py def post(self, request): name = request.POST.get("name", None) date = request.POST.get("date", None) status = request.POST.get("status", None) description = request.POST.get("description", None) Attendance.objects.create(name=name, date=date, status=status, description=description) return redirect("attendance_list")
post
함수 내에서name
으로 선언한 변수가 바로 위의html
파일 내에서 사용한 템플릿 변수attendance.name
의name
을 의미.- 그리고
post
함수 내에서name
변수에게request
함수를 통해 생성한 값을 할당해주었는데, 이 함수 내의 변수"name"
은models.py
에서 정의한Attendance
모델의field
이름을 뜻함.# models.py class Attendance(models.Model): NONE = "NO" ATTENDANCE = "AT" ABSENT = "AB" PART = "PT" STATUS_CHOICES = [ (NONE, "미지정"), (ATTENDANCE, "출석"), (ABSENT, "결석"), (PART, "일부참여"), ] name = models.CharField(verbose_name="이름", max_length=10) date = models.DateField(verbose_name="날짜") status = models.CharField( verbose_name="출석 여부", max_length=2, choices=STATUS_CHOICES, default=NONE ) description = models.TextField(verbose_name="비고", blank=True) def __str__(self): return f"출석부 : {self.name} ({self.date})" class Meta: verbose_name = "출석부" verbose_name_plural = "출석부 목록"
- 현재
Attendance
모델은ChoiceField
를 사용하였는데, 이는enrolled.html
에서form
을 이용하여 자료를 입력받을 때 사용.- 예를 들어,
ATTENDANCE = "AT"
라는 부분을 보게 되면,ATTENDANCE
라는 변수에"AT"
라는 값을 할당해주게 되는 것이고,STATUS_CHOICE
리스트에서 그"AT"
라는 값과"출석"
이라는 값을tuple
형태로 매칭.- 또한 사용자가 화면을 통해
form
을 작성하여 선택하여 POST 요청을 할 경우,"AT"
라는 값이 서버로 넘어오게 됨.# enrolled.html <div class="form-item"> <div class="title">출석여부</div> <div class="radio-wrap"> <input type="radio" name="status" value="AT"> <label for="attendance">출석</label> </div> <div class="radio-wrap"> <input type="radio" name="status" value="AB"> <label for="absent">결석 (사유 필히 작성)</label> </div> <div class="radio-wrap"> <input type="radio" name="status" value="part"> <label for="complete">일부 일정 불참 (사유 필히 작성)</label> </div> </div>
- 위에서 보시다 시피,
input
태그 내의value
값으로 해당 변수의 데이터가 동일하게 기재가 되어 있어야함.
{% extends 'base.html' %}
{% block content %}
<div>
<form method="post" action="">
{% csrf_token %}
<div class="form-item">
<div class="title">이름</div>
<input class="input-box" type="text" name="name" value="">
</div>
<div class="form-item">
<div class="title">날짜</div>
<input class=""input-box" type="date" name="date" value="">
</div>
<div class="form-item">
<div class="title">출석여부</div>
<div class="radio-wrap">
<input type="radio" name="status" value="AT">
<label for="attendance">출석</label>
</div>
<div class="radio-wrap">
<input type="radio" name="status" value="AB">
<label for="absent">결석 (사유 필히 작성)</label>
</div>
<div class="radio-wrap">
<input type="radio" name="status" value="PT">
<label for="part">일부 일정 불참 (사유 필히 작성)</label>
</div>
</div>
<div class="form-item">
<div class="title">사유</div>
<div class="textarea-wrap">
<textarea name="description" form-items="8" cols="50"></textarea>
</div>
</div>
<div class="form-item">
<button class="button-bg-full" type="submit">제출하기</button>
<button class="button-bg-empty" type="button" onclick="location.href='{% url 'attendance_list' %}'">목록보기</button>
</div>
</form>
</div>
{% endblock content %}
URL Template Tag
작성 관련
{% url 'attendance_list' %}
urls.py
파일에서url name
이attendance_list
로 되어 있는url
로 연결해주는 경로임을 의미.# urls.py urlpatterns = [ path("admin/", admin.site.urls), path("attendance/", AttendanceView.as_view(), name="attendance_list"), path("attendance/create/", AttendanceCreateView.as_view(), name="attendance_create"), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- 현재 이 경우에는 웹브라우저를 통해
기본 주소/attendance/
로 접속 시, 우리가 미리 지정한html
화면을 보여주겠다는 것을 의미.- 지정한
html
파일이 무엇인지 확인하기 위해서는 위의 경로에서 사용한View
함수로 가서 확인해보면 됨.# views.py class AttendanceView(TemplateView): template_name = "attendance/list.html" def get_context_data(self, *args, **kwargs): attendance_qs = Attendance.objects.all().order_by("-date") context = {} context["attendance_qs"] = attendance_qs return context
- 위의 함수 내에서
template_name = "attendance/list.html
부분을 통해, 이 함수가template/attencance/list.html
의 위치에 해당하는html
파일을 url에 연결해준다는 것을 알 수 있음.