티스토리 뷰
템플릿은 뷰함수에서 응답하는 html 파일이다.
템플릿이 저장되는 위치는 이미 정해져 있다.
mysite/setting.py
에서, 템플릿 환경 설정을 쓴다.
TEMPLATES = [
dirs에다 경로 지정을 한다.
]
Installed_APPS 에 존재하는 app들의 하위에도 위치할 수 있다.
예를 들어 앱 이름이 blog면, blog/temlplates과 같은 의미이다.
첫번째로 dirs에서 찾고, 그 다음에 순서대로 install app에 등록된 순서대로 템플릿을 검색하게 된다.
'DIRS' : [BASE_DIR / 'templates'] ,
templates 폴더를 추가해서, html을 넣는다.
이러면 공통으로 사용하는 템플릿을 mysite에 추가해서 넣어주면 된다.
만약 각각 쓰려면 blog/templates 처럼 주면 된다.
list.html이라고 만들어서, 대충 http를 만든다.
<h1> Post 목록 보기 </h1>
render
명령문
blog/views.py
from django.shortcuts import render
render(HttpRequest, Template, [context])
blog/views.py
def list(request):
return render(request,'list.html')
http를 응답하게 만들어주는 게 render 함수이다.
인자값을 3개를 줘야 한다. http request와 temlplate, 그리고 context는 선택이다.
템플릿 응답
context는 뷰에서 템플릿으로 전달하는 데이터를 말합니다.
context는 key:value 형식의 딕셔너리 타입으로 지정합니다.
뷰에서 썼던 데이터를 전달하고 싶다고 하면 딕셔너리 형태로 전달하면 된다.
def list(request):
post_list = Post.objects.all()
return render(request,'list.html',{'post_all':post_list})
그러면 해당 템플릿에 해당 post_list가 전달된다.
그리고 html에 이렇게 추가하면 된다.
{{post_all}}
이렇게 하면 해당 변수를 받는다는 의미이다.
그런데 templte의 이름은 중복이 일반적으로 일어난다.
그렇기에 blog/templates/blog/list.html과 같은 경로로 만든다.
shop/templates/shop/list.html
이런 상대로 하고, blog/list.html
shop/list.html로 넣는다.
템플릿에 온 변수들을 활용하기
post_all을 for문을 돌려볼 수 있다.
{% for 변수 in iterable 객체 %}
반복실행문
{% endfor %}
여기서는
{%for post in post_all %}
{{post.id}}
{{post.title}}
{{post.body}}<br>
{% endfor %}
마찬가지로 detail도 고쳐본다.
views.py
def detail(request, id):
post = get_object_or_404(Post,id=id)
return render(request, 'blog/detail.html', {'post': post})
blog/detail.html
<h1> {{post.title}} </h1>
제목 : {{post.title}} <br>
내용 : {{post.body}} <br>
다음과 같이 만든다.
그리고 이제 두 페이지가 연결될 수 있도록 한다.
<h1> Post 목록 보기 </h1>
{%for post in post_all %}
<a href="{{post.id}}"> {{post.title}}</a><br>
{% endfor %}
{% comment %} 출력이라는 의미 {% endcomment %}
if 태그 써보기
veiw.py에서 테스트를 넣는다.
def test4(request):
return render(request, 'bloh/test4.html',{'score':95})
그리고 test4.html을 만들어서 if else문을 넣는다.
새로운 클래스가 만들어졌으므로, path에 추가하는 것도 잊지 말자.
path('test4/', views.test4),
{% if score >= 60 %}
합격!
{% else %}
불합격!
{% endif %}<br>
<hr>
{{var | linebreaks}}
{% comment %} 필터를 적용한다. linebraks는 줄바꿈을 적용한다. {% endcomment %}
<hr>
{{var | truncatechars:100}}
{% comment %} 100개의 글자만 보여지게 할 수 있다. {% endcomment %}
필터
아래에 있는 건 필터이다.
{{값 | 필터}}
{{ 값 1 | 필터 : 값2}}
{{값1 | 필터 1: 값2 } 필터 2}}
시간 설정
setting.py
Lanugae_code ="ko-kr"
time_znoe = "Aisa/Seoul"
USE_I18N = True
USE_TZ = True
혹은
blog/views.py에서 설정할 수 있다.
from django.utils import timezone
def test6(request):
d1 = timezone.now()
d2 = timezone.datetime(2001,3,19)
d3 = timezone.datetime(2030,3,19)
return render(request, 'blog/test4.html', {'date1':d1, 'date2':d2, 'date3':d3})
문법으로는 {{미래날짜 | timeuntil}}
{{d1}} <br>
{{d1|date: "Y-m-d"}} <br>
{{d1|time: "P" }} <br>
{{d2|timesince}}<br>
{{d3|timeuntil}}<br>
https://docs.djangoproject.com/en/4.2/ref/templates/builtins/#date
해당하는 시간에 대한 포맷팅을 넣어줘야 한다.
timesince는 {{ 과거날짜 | timesince : 미래날짜}}로 쓴다. 과거부터 미래날짜까지 시간을 알려준다.
timeuntil은 {{미래날짜 | timeuntil: 미래날짜2}}로 쓴다. 미래날짜부터 미래날짜2까지 시간을 알려준다.
템플릿 상속
원래 있던 템플릿을 상속받아서 사용할 수 있다.
부모 템플릿은 공통 코드를 구현한다.
자식이 채워넣어야 하는 부분을 영역 설정해준다.
{% block 이름 %}
{% endblock %}
자식 템플릿은 부모 템플릿 경로를 써넣어준다.
여기서는 layout.html을 사용한다.
mysite/아래 templates에 가져다 놓는다. mysite/mysite 아니다. 거기에 넣으면 인식 못한다.
{% extends "부모템플릿 경로" %}
{% extends "layout.html" % }
blog/templates/blog/list.html
이 경로에 있는 것 상속받아본다. mysited에 있으므로, 위 코드와 같이 넣어도 된다.
여기서는 2개를 채워넣을 수 있다.
<html>
<head>
<meta charset="utf-8" />
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<style>
html {position: relative; min-height: 100%}
body{margin-bottom: 60px}
#page-footer{
position: absolute;
bottom: 0;
width:100%;
height: 60;
line-height: 60px;
background-color: #f5f5f5;
}
</style>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="/blog/">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">회원 가입 </a> </li>
<li><a href="#">로그인</a></li>
<li><a href="#">프로필</a> </li>
<li><a href="#">로그 아웃</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-sm-12">
{% block content %}
{% endblock %}
</div>
</div>
</div>
<div id="page-footer">
<div class="container">
<p class="text-muted">
Copyright © 2020 KINO Data Systems All Right Reserved
</p>
</div>
</div>
</body>
</html>
title과 content를 채워넣는다.
{% extends "layout.html" %}
{% block title %}
Post 목록
{% endblock %}
{% block content %}
<h1> Post 목록 보기 </h1>
{%for post in post_all %}
<a href="{{post.id}}"> {{post.title}}</a><br>
{% endfor %}
{% comment %} 출력이라는 의미 {% endcomment %}
{% endblock %}
detail에도 같은 방식으로 채워준다.
{% extends "layout.html" %}
{% block title %}
{% endblock title %}
{% block content %}
<h1> {{post.title}} </h1>
제목 : {{post.title}} <br>
내용 : {{post.body}} <br>
{% endblock content %}
실습
1:N 관계를 수정해준다.
detail에서 comment_list를 추가
def detail(request, id):
post = get_object_or_404(Post,id=id)
comment_list =post.comments.all()
return render(request, 'blog/detail.html', {'post': post, 'comment_all':comment_list})
detail.html에서도 수정해준다.
{% block content %}
<h1> {{post.title}} </h1>
제목 : {{post.title}} <br>
내용 : {{post.body}} <br>
<hr>
<p>댓글</p>
{% for comment in comment_all %}
<p> {{comment.message}}/{{comment.author}}/{{comment.updated}}</p>
{% empty%}
댓글이 존재하지 않습니다.
{% endfor %}
{% endblock content %}
만약에 버그가 있다면, models의 comments에서, 사용자 정의가 되어 있는지 봐보자.
post= models.ForeignKey(Post, on_delete=models.CASCADE,related_name='comments')
1:1 관계
veiws.py
from .models import User
def profile(request):
user = User.objects.get(id=1)
return render(request, 'blog/profile.html', {'user': user})
사용자 이름을 불러온다.
그리고 profile.html에서 새로운 html을 만들어준다.
{% extends "layout.html" %}
{% block title %} Profile {% endblock title %}
{% block content %}
<h1>{{ user.name }}'s Profile</h1>
<ul>
<li>이름 : {{ user.name }}</li>
<li>전화번호 : {{ user.profile.phone_number }}</li>
<li>주소 : {{ user.profile.address }}</li>
</ul>
{% endblock content %}
당연히 새 페이지가 추가되었으니, urls.py에도 추가해준다.
path(('profile/', views profile)
그리고, templates/layout.html을 수정해준다.
<ul class="nav navbar-nav navbar-right">
<li><a href="#">회원 가입 </a> </li>
<li><a href="#">로그인</a></li>
<li><a href="/blog/profile/">프로필</a> </li>
<li><a href="#">로그 아웃</a></li>
</ul>
</div>
프로필을 누르면 해당 페이지로 갈 수 있게 해준다.
N:M 관계
디테일에서 tag_list도 추가해준다.
views.py이다.
def detail(request, id):
post = get_object_or_404(Post,id=id)
comment_list =post.comments.all()
tag_list = post.tag.all()
return render(request, 'blog/detail.html', {'post': post, 'comment_all':comment_list,
'tag_list':tag_list})
detail.html에서 태그를 추가해준다.
당연히 content란 안이다.
<hr>
<p>태그</p>
{% for tag in tag_list %}
#{{tag.name}}
{% endfor %}
모델에 있는 태그를 누르면, 해당 태그와 연관된 포스트를 보려면
blog/views.py
from .models import Tag
def tag_list(request, id):
tag = Tag.objects.get(id=id)
post_list = tag.post_set.all()
return render(request, 'blog/list.html', {'post_all': post_list})
urls.py
path('tag/<id>/', views.tag_list),
detail.html
<p>태그</p>
{% for tag in tag_list %}
<a href="/blog/tag/{{tag.id}}">{{tag.name}}</a>
{% endfor %}
다음과 같이 하면 된다.