1, 2편에 이어 본 블로그에서는 게시판 다운 화면을 구성하기 위해 html( view)페이지를 꾸며본다. ( 꾸민다고 했지만 이쁘진 않다 ^^; ) 진행하기 전에 전 블로그에서 다룬 model이 구성되어 있어야 원활한 진행이 가능하다.
2021/02/01 - [python/Django] - 1. 게시판 만들기 - Django 3.x 설치 및 핵심개념 파악
2021/02/01 - [python/Django] - 2. 게시판 만들기 - Django + mariaDB 연동( 접속부터 모델생성까지 - migration )
2021/02/04 - [python/Django] - 4. 게시판 만들기 - Django 게시판 페이징(Pagination) 처리( feat. GIF )
결과물은 다음과 같다. 페이지는 3개 페이지로 구성(index, detail, write)되며 detail 페이지에서 댓글을 달 수 있는 기능이 있다. 페이징 기능은 다음편에서 다루도록 한다.
board/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils import timezone
from django.urls import reverse
from .models import Board
def index(request):
all_boards = Board.objects.all().order_by("-pub_date") # 모든 데이터 조회, 내림차순(-표시) 조회
return render(request, 'board/index.html', {'title':'Board List', 'board_list':all_boards})
def detail(request, board_id):
board = Board.objects.get(id=board_id)
return render(request, 'board/detail.html', {'board': board})
def write(request):
return render(request, 'board/write.html')
def write_board(request):
b = Board(title=request.POST['title'], content=request.POST['detail'], author="choi", pub_date=timezone.now())
b.save()
return HttpResponseRedirect(reverse('board:index'))
def create_reply(request, board_id):
b = Board.objects.get(id = board_id)
b.reply_set.create(comment=request.POST['comment'], rep_date=timezone.now())
return HttpResponseRedirect(reverse('board:detail', args=(board_id,)))
-
index: 게시글 목록
-
detail: 게시글 제목 선택 시 상세 페이지 이동
-
write: 게시글 목록에서 "글쓰기" 버튼 클릭 시 쓰기 페이지 이동
-
write_board: 쓰기 페이지에서 새로운 글을 등록 시에 submit 처리
-
create_reply: 상세 페이지에서 댓글 등록 시에 submit 처리
- POST 데이터 전송(저장) 후 HttpResponseRedirect 를 사용하여 사용자가 뒤로 가기를 했을때 두번 POST 전송 처리 되지 않게 한다.
board/urls.py
from django.urls import path
from . import views
app_name = 'board'
urlpatterns = [
path('', views.index, name='index'),
path('<int:board_id>/', views.detail, name='detail'),
path('write/', views.write, name='write'),
path('write/write_board', views.write_board, name='write_board'),
path('<int:board_id>/create_reply', views.create_reply, name='create_reply'),
]
app_name은 아래와 같이 템플릿에서 네임스페이스 접근을 위해 사용된다.
<a href="{% url 'board:detail' data.id %}">
{{ data.title }}
</a>
board/templates/board/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style type="text/css">
thead {
background-color:#cecece;
}
.content {
max-width:500px;
margin: auto;
padding:10px;
}
.header {
text-align: center;
}
.board {
width: 100%
}
.even_bgcolor {
background-color:#e8efff;
}
</style>
<body>
<div class="content">
<div class="header">
<h2>{{ title }}</h2>
</div>
<div style="text-align:right">
<a href="{% url 'board:write' %}">글쓰기</a>
</div>
<table class="board">
<thead>
<tr class="header">
<th style="width:10%;">순번</th>
<th style="width:60%">제목</th>
<th style="width:30%">작성일자</th>
</tr>
</thead>
<tbody>
{% if board_list %}
{% for data in board_list %}
<tr class="{% if forloop.counter|divisibleby:2 %}even_bgcolor{% endif %}">
<td style="text-align:center;">{{ forloop.counter }}</td>
<td>
<a href="{% url 'board:detail' data.id %}">
{{ data.title }}
</a>
</td>
<td>{{ data.pub_date|date:'Y-m-d' }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td>작성된 게시글이 없습니다.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</body>
</html>
-
{{ data.pub_date|date:'Y-m-d' }} 에서 date는 Django Filter 기능으로 datetime형태의 pub_date를 포맷변환한다. 더 자세한 내용은 여기를 참조한다.
-
짝수 행에 대해 even_bgcolor style을 입혀준다. cycle을 사용하여 for를 사용한 반복문에 홀수, 짝수를 구할 수 있다.
<tr class="{% cycle '' 'even_bgcolor' %}">
board/templates/board/detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style type="text/css">
.content {
max-width:500px;
margin: auto;
padding:10px;
}
.reply_content {
text-align:right
}
.reply_content .reply{
border-radius: 0.5em;
display: block;
margin: 4px;
padding: 3px 10px;
}
.board_for_read {
width: 100%;
background-color:#f1f1f1;
}
#title {
height: 32px;
width: 100%;
border-radius: 0.5em;
border: none;
font-family: inherit;
font-size: inherit;
background: none;
}
textarea {
width: 100%;
font-family: inherit;
font-size: 100%;
resize: none;
border-radius: 0.5em;
padding-block: 10px;
border: 0px;
background: none;
}
.td_title {
background-color: #d8d8d8
}
</style>
<body>
<div class="content">
<table class="board_for_read">
<tbody>
<tr>
<td class="td_title" style="text-align:center; width:20%;">제목</td>
<td style="padding:10px;">
<input type="text" name="title" id="title" value="{{ board.title }}" readonly/>
</td>
</tr>
<tr>
<td class="td_title" style="text-align:center; width:20%;">작성일자</td>
<td style="padding:10px;">
<span>{{ board.pub_date }}</span>
</td>
</tr>
<tr>
<td class="td_title" style="text-align:center;">내용</td>
<td style="padding:10px;">
<textarea name="detail" id="detail" rows="10" readonly>{{ board.content }}</textarea>
</td>
</tr>
</tbody>
</table>
<div style="text-align:left;">
<a href="{% url 'board:index' %}">> Home</a>
</div>
<form action="{% url 'board:create_reply' board.id %}" method="post">
{% csrf_token %}
<table class="board_for_read">
<tbody>
<tr>
<td colspan="2" class="td_title" style="text-align:left; padding-left:10px; height:30px;">leave a comment</td>
</tr>
<tr>
<td style="text-align:center;">
<input type="text" name="comment" id="comment" style="width:100%">
</td>
<td><input type="submit" value="save"></td>
</tr>
</tbody>
</table>
</form>
<div class="reply_content">
{% for rep in board.reply_set.all %}
<span class="reply">{{ rep.comment }} [{{ rep.rep_date|date:'Y-m-d H:i'}}]</span>
{% endfor %}
</div>
</div>
</body>
</html>
-
POST 형식으로 데이터를 전송하기 위해선 데이터 위조방지를 위해 form 태그 내 {% csrf_token %} 이 필요하다.
board/templates/board/write.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style type="text/css">
.content {
max-width:500px;
margin: auto;
padding:10px;
}
.board_for_read {
width: 100%;
background-color:#f1f1f1;
}
#title {
height: 32px;
width: 100%;
border-radius: 0.5em;
border: none;
font-family: inherit;
font-size: inherit;
}
textarea {
width: 100%;
font-family: inherit;
font-size: 100%;
resize: none;
border-radius: 0.5em;
padding-block: 10px;
border: 0px;
}
.td_title {
background-color: #d8d8d8
}
</style>
<body>
<div class="content">
<form action="{% url 'board:write_board' %}" method="post">
{% csrf_token %}
<div style="text-align:right;padding: 5px;">
<input type="submit" value="저장">
</div>
<table class="board_for_read">
<tbody>
<tr>
<td class="td_title" style="text-align:center; width:20%;">제목</td>
<td style="padding:10px;">
<input type="text" name="title" id="title" value="{{ board.title }}"/>
</td>
</tr>
<tr>
<td class="td_title" style="text-align:center;">내용</td>
<td style="padding:10px;">
<textarea name="detail" id="detail" rows="10">{{ board.content }}</textarea>
</td>
</tr>
</tbody>
</table>
</form>
<div style="text-align:left;">
<a href="{% url 'board:index' %}">> Home</a>
</div>
</div>
</body>
</html>
마치며..
화면의 기능이 추가될 수록 Django templates에 더 깊은 이해가 필요한것 같다. 여기선 정말 간단한 기능의 게시판만 적용하였으나 여유가 된다면 비밀번호 기능을 추가한다거나 파일첨부 기능을 추가해 보는 것도 좋을것 같다. 다음 편에선 페이징 기능을 적용해보도록 한다.
2021/02/04 - [python/Django] - 4. 게시판 만들기 - Django 게시판 페이징(Pagination) 처리( feat. GIF )
'python > Django' 카테고리의 다른 글
1. Django with bootstrap, 웹페이지 기본 프레임 및 메뉴 구성( top, left, main ) (3) | 2021.02.26 |
---|---|
4. 게시판 만들기 - Django 템플릿 & 페이징(Pagination) 처리( feat. GIF ) (0) | 2021.02.04 |
Django templates 날짜(datetime) 포맷 변경 및 UTC 설정 (0) | 2021.02.03 |
2. 게시판 만들기 - Django + mariaDB 연동( 접속부터 모델생성까지 - migration ) (0) | 2021.02.01 |
1. 게시판 만들기 - Django 3.x 설치 및 핵심개념 파악 (0) | 2021.02.01 |