웹 애플리케이션에서 HTML 구조를 재사용하게 해주는 기능이다. 공통적인 HTML 구조를 기본 템플릿에 정의하고, 각 페이지에서 이를 상속받아 사용한다.
기본 템플릿에서는 {% block %} 태그를 사용해 자식 템플릿에서 재정의할 수 있는 영역을 지정한다. 이런 방식으로 웹사이트의 일관성을 유지하면서도 각 페이지를 개별적으로 개발할 수 있다. 공통 요소의 변경이 필요할 때는 기본 템플릿만 수정하면 된다.
pip install django
django-admin startproject tutorialdjango .
python manage.py migrate
python manage.py startapp main
python manage.py startapp blog
프로젝트명 > settings.py
ALLOWED_HOSTS = ["*"]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"추가한 앱 이름",
]
''
'about/'
'contact/'
'blog/'
'blog/<int:pk>/'
앱이름: main
URL views 함수이름 html 파일이름 비고
'' index index.html
'about/' about
'contact/' contact
앱이름: blog
URL views 함수이름 html 파일이름 비고
'blog/' blog blog.html
'blog/<int:pk>' post post.html 게시물이 없을 경우에는 404로 연결
기본 프로젝트의 urls.py
와 각 앱마다 urls.py
를 정의하고 views.py
에서 urlpatterns
의 함수들을 정의한다.
main > urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("about/", views.about, name="about"),
path("contact/", views.contact, name="contact"),
]
템플릿에서 name
의 값으로 접근 가능하다.
blog > urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.blog_list, name="blog_list"),
path("<int:pk>/", views.blog_detail, name="blog_detail"),
]
blog > views.py
from django.shortcuts import render
blog_database = [
{
"id": 1,
"title": "제목1",
"content": "내용1",
"created_at": "2021-02-22",
"updated_at": "2021-02-22",
"author": "홍길동",
"category": "일상",
"tag": ["태그1", "태그2"],
"view_count": 0,
"thumbnail": "https://picsum.photos/200/300",
"like_count": 3,
"like_user": [10, 20, 21],
},
{
"id": 2,
"title": "제목2",
"content": "내용2",
"created_at": "2021-02-23",
"updated_at": "2021-02-23",
"author": "김철수",
"category": "일기",
"tag": ["태그1", "태그3"],
"view_count": 0,
"thumbnail": "https://picsum.photos/200/300",
"like_count": 10,
"like_user": [10, 20, 21, 22, 23, 24, 25, 26, 27, 28],
},
{
"id": 3,
"title": "제목3",
"content": "내용3",
"created_at": "2021-02-24",
"updated_at": "2021-02-24",
"author": "이영희",
"category": "맛집",
"tag": ["태그1", "태그3"],
"view_count": 0,
"thumbnail": "https://picsum.photos/200/300",
"like_count": 20,
"like_user": [10, 20, 21, 22, 23, 24, 25, 26, 27, 28],
},
{
"id": 4,
"title": "제목4",
"content": "내용4",
"created_at": "2021-02-25",
"updated_at": "2021-02-25",
"author": "박민수",
"category": "여행",
"tag": ["태그1", "태그3"],
"view_count": 0,
"thumbnail": "https://picsum.photos/200/300",
"like_count": 30,
"like_user": [10, 20, 21, 22, 23, 24, 25, 26, 27, 28],
},
]
def blog_list(request):
context = {"blog_list": blog_database}
return render(request, "blog/blog_list.html", context)
def blog_detail(request, pk):
context = {"blog": blog_database[pk - 1]}
return render(request, "blog/blog_detail.html", context)
render(request, html파일, context(딕셔너리 형태)
request
: 사용자가 보내는 요청에 대한 정보(로그인 정보 등){{ variable }}
: 렌더링 시 해당 변수의 값으로 치환{% for %}
{% endfor %}
{{name|lower}}
: name의 값을 소문자로 변환하여 출력 등# 상속해주는 부분(수정할 특정 부분)에 다음과 같이 선언
{% block 자식이름 %}
{% endblock %}
{% extends '부모html파일명' %}
# 부모의 대부분의 내용을 상속받고 해당 부분만 수정하겠다!
{% block 자식이름 %}
... 실제 사용할 자식 코드 ...
{% endblock %}
# templates > base > base.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>weniv blog</title>
</head>
<body>
<header>
<h1>weniv blog</h1>
<nav>
<ul>
<li>메뉴1</li>
<li>메뉴2</li>
<li>메뉴3</li>
</ul>
</nav>
</header>
<main>
{% block contents %}
<p>test 이어서 써집니다1</p>
<p>test 이어서 써집니다2</p>
{% endblock %}
</main>
<footer>
<p>저작권은 weniv에게 있습니다.</p>
</footer>
</body>
</html>
# templates > blog > blog_list.html
{% extends 'base/base.html '%}
{% block contents %}
<h1>bloglist</h1>
<ul>
{% for blog in blog_list %}
<li>
{{ forloop.counter }}
<a href="{% url 'blog_detail' blog.id %}">{{ blog.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
extends
라는 선언으로 부모의 html을 상속받고 있으며, % block contents %
로 수정할 부분을 정의하고 있다.
해당 부분을 제외한 부분은 부모를 그대로 따라간다.
여기서 block
뒤에오는 contents
는 block
이름으로, 다른 이름이 들어가도 상관없다.
{{ forloop.counter }}
부분은 현재 반복문이 몇 번째 루프인지를 나타낸다. 첫 번째 루프에서는 1을 반환하는 그런 거라고 생각하면 된다.