(2024.07.01. 수정됨.)
주요 파일 경로
blog
|- entry
| |- forms.py
|- templates
|- base.html
|- style.html
|- is_login.html
|- home.html
|- index.html
|- detail.html
|- post.html
페이지마다 html을 어떻게 꾸미고 사용할지 생각하고 결정하는 것은 정말 어렵습니다.
특히 사이트 디자인 부분은 너무 어려워서 자신없는 분야이기도 한데요.
python이 다른 파일에 저장된 코드를 import할 수 있는 것처럼, 장고는 템플릿이 다른 템플릿을 가져와서 사용할 수 있는 기능을 제공하고 있습니다.
템플릿 작성하기
기본 베이스 템플릿과 기타 템플릿을 작성하고, 각 템플릿을 가져와서 사용하는 방법을 알아보겠습니다.
기본 베이스 작성하기
먼저 사이트 html의 기본 틀이 될 베이스 템플릿을 작성합니다.
# templates/base.html
<head>
{% include 'style.html' %}
</head>
<body>
<header>
<p><a href="/"><span style="font-size: 28px;"><b>하얀설표 블로그</b></span></a></p>
</header>
<hr>
{% include 'is_login.html' %}
<hr>
<h1>{% block title %}{% endblock %}</h1>
<hr>
<main>
{% block main %}{% endblock %}
</main>
<hr>
</body>
<footer>
<p>this site Powered by <a href="https://www.djangoproject.com/">Django</a></p>
<p>Designed by 하얀설표 from <a href="https://django.seolpyo.com/">설표의 장고</a></p>
</footer>
{% include ~ %}
include는 다른 템플릿을 가져와서 사용하는 템플릿 필터입니다.
{% block ~ %}
block은 현재 템플릿을 불러와서 하위 템플릿에 사용하는 경우, 하위 템플릿에서 추가 내용을 입력하기 위한 공간입니다.
block 필터는 반드시 {% endblock %}으로 닫혀야 합니다.
css 작성하기
base.html을 보면 head 영역 사이에 {% include 'style.html' %} 명령을 넣어두었습니다.
이는 style.html을 불러와서 지정된 위치에 삽입해서 사용하겠다는 뜻입니다.
다음과 같이 style.html을 작성해줍니다.
# templates/style.html
<style>
body {
width: 900px;
margin-left: auto; margin-right: auto;
border-left: #000 1px solid; border-right: #000 1px solid;
padding-left: 10px; padding-right: 10px;
}
main { min-height: 400px; }
footer {
width: 900px;
margin-left: auto; margin-right: auto;
padding-left: 10px; padding-right: 10px;
text-align: center;
}
input[name=title] {
width: 100%;
font-size: 26px; font-weight: bold;
padding-top: 5px;
}
</style>
로그인 템플릿 작성하기
style.html과 마찬가지로 로그인 상태를 확인하고, 로그인과 로그아웃 버튼을 제공하는 html을 include로 불러와 사용합니다.
base.html의 {% include 'is_login.html' %} 부분입니다.
is_login.html을 다음과 같이 작성해줍니다.
admin url은 장고에서 기본으로 제공하는 admin app을 사용해서 app_name을 지정하지 않았지만, 기본적으로 "admin"이라는 app_name을 가지고 있습니다.
# templates/is_login.html
{% if request.user.is_anonymous %}
<div>
<p>로그인하지 않았습니다.</p>
<a href="{% url 'admin:login' %}?next={{ request.get_full_path }}">로그인하기</a>
</div>
{% else %}
<p>"{{ request.user.username }}"님</p>
<form action="{% url 'admin:logout' %}?next={{ request.get_full_path }}" method="post">
{% csrf_token %}
<input type="submit" value="로그아웃">
</form>
{% endif %}
홈페이지 템플릿 수정하기
기본 뼈대가 base.html에 들어있기 때문에 이를 상속받으면 home.html에는 3줄의 코드만 작성해주면 됩니다.
# templates/home.html
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block main %}{{ content|safe }}{% endblock %}
{% extends ~ %}
extends는 다른 템플릿을 상속받아 사용하는 템플릿 필터입니다.
앞서 작성한 base.html을 상속받았으며, base.html에 존재하는 title block과 main block에 각각 데이터를 집어넣었습니다.
글 목록 템플릿 수정하기
글 목록 페이지에서 사용할 html도 간소화할 수 있습니다.
템플릿을 수정하면서 url도 url 필터를 이용하여 프로젝트가 알아서 url을 찾아넣도록 해줍니다.
# templates/index.html
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block main %}
<div>
<a href="{% url 'entry:post' %}">글 작성하기</a>
</div>
<hr>
<article>
{% for object in objects %}
<p><a href="{{ object.get_absolute_url }}">{{ object.title }}</a></p>
{% empty %}
<p>작성된 글이 없습니다.</p>
{% endfor %}
</article>
{% endblock %}
개별 글 템플릿 수정하기
개별 글 조회 페이지에서 사용할 템플릿도 수정합니다.
수정하면서 글 목록 페이지로 이동할 수 있는 링크도 삽입했습니다.
# templates/detail.html
{% extends 'base.html' %}
{% block title %}{{ object.title }}{% endblock %}
{% block main %}
<div>
<a href="{% url 'entry:index' %}">글 목록</a>
<a href="{% url 'entry:edit' object.pk %}">글 수정하기</a>
<a href="{% url 'entry:delete' object.pk %}">글 삭제하기</a>
</div>
<hr>
<div>
<p>작성 시간 : {{ object.date_post }}</p>
<p>수정 시간 : {{ object.date_edit }}</p>
</div>
<hr>
<article>
{{ object.content|safe }}
</article>
{% endblock %}
글 작성과 수정 페이지 템플릿 수정하기
글 작성과 수정에 사용하는 html도 수정합니다.
수정하면서 글 작성을 취소했을 때 글 목록 페이지로, 글 수정을 취소했을 때는 글 조회 페이지로 이동할 수 있는 링크를 삽입했습니다.
# templates/post.html
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block main %}
<div>
{% if pk %}
<a href="{% url 'entry:detail' pk %}">편집 취소</a>
{% else %}
<a href="{% url 'entry:index' %}">작성 취소</a>
{% endif %}
</div>
<hr>
<form method="post" action="{% if not pk %}{% url 'entry:save' %}{% else %}{% url 'entry:save' pk %}{% endif %}">
{% csrf_token %}
{{ form }}
<input type="submit" value="저장하기">
</form>
{% endblock %}
forms.py 수정하기
forms.py를 다음과 같이 수정해줍니다.
form class의 Meta에 widgets라는 variable을 추가하면 페이지를 구현할 때 간섭할 수 있게 됩니다.
textinput이나 textarea의 경우 placeholder를 추가하면 해당 field가 공란일 때 표시되는 문구를 지정할 수 있습니다.
labels를 통해 각 filed에 표시되는 명칭을 관리할 수 있습니다.
이전에는 이를 설정하지 않아 "title"과 "content"라는 문구가 노출되었었는데, 공란으로 바꿔 더 이상 노출되지 않도록 했습니다.
이제부터는 placeholder를 통해 각 field가 무엇을 입력하는 공간인지 표현될 것이기 때문입니다.
from django import forms
from django_summernote.widgets import SummernoteWidget
from .models import Post
class Form(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
widgets = {
'title': forms.widgets.TextInput(attrs={'placeholder': '제목을 입력해주세요.',}),
# 'content': forms.widgets.Textarea(attrs={'placeholder': '내용을 입력해주세요.',}),
'content': SummernoteWidget(),
}
labels = {
'title': '',
'content': '',
}
SummernoteWidget
SummernoteWidget은 django-summernote에서 제공하는 widget입니다.
이전에 장고 프로젝트에 summernote 에디터를 추가해서 사용하고 있기 때문에 content field는 forms.widgets.Textarea이 아닌 SummernoteWidget을 widget으로 사용합니다.
확인해보기
조잡하지만(ㅠㅠ) 이전보다는 나은 페이지를 조회할 수 있게 되었습니다.
header에 "하얀설표 블로그"라는 a 태그를 추가하고 href값을 "/"으로 설정했기 때문에 언제든 header를 클릭하면 홈페이지로 이동할 수 있게 되었습니다.
header 아래에서는 현재 로그인 상태와 로그인 상태에 따라 로그인 또는 로그아웃 버튼을 확인할 수 있습니다.
글 작성 페이지를 보면 이전과는 다른 화면이 보이는데, 이는 summernote라는 위지위그 에디터를 적용한 상태이기 때문입니다.

이 글의 댓글 기능은 일부러 막아놓았습니다. 궁금한 내용이 있다면 게시판을 이용해주세요!