게시판 예시
DB
models.py
from django.db import models
# Create your models here.
class BoardTab(models.Model):
name = models.CharField(max_length = 20)
passwd = models.CharField(max_length = 20)
mail = models.CharField(max_length = 30)
title = models.CharField(max_length = 100)
cont = models.TextField()
bip = models.GenericIPAddressField()
bdate = models.DateTimeField()
readcnt = models.IntegerField()
gnum = models.IntegerField()
onum = models.IntegerField()
nested = models.IntegerField()
settings.py
"""
Django settings for django9_board project.
Generated by 'django-admin startproject' using Django 4.1.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-h#p-an0ts3wjcr8*8e*-+j21sxb#$u^3*36o3vp7=p^ifodjkq"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"myboard",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "django9_board.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "django9_board.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'boarddb',
'USER': 'root',
'PASSWORD': '123',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
]
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
LANGUAGE_CODE = "ko-kr"
TIME_ZONE = "Asia/Seoul"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
urls.py
from django.contrib import admin
from django.urls import path
from myboard.views import view1
from django.urls.conf import include
urlpatterns = [
path("admin/", admin.site.urls),
path('', view1.mainFunc),
path('board/', include('myboard.urls')),
]
urls.py (myboard)
from django.urls import path
from myboard.views import view1, view2
urlpatterns = [
path('list', view1.listFunc),
path('insert', view1.insertFunc),
path('insertok', view1.insertOkFunc),
path('search', view1.searchFunc),
path('content', view1.contentFunc),
path('update', view1.updateFunc),
path('updateok', view1.updateOkFunc),
path('delete', view1.deleteFunc),
path('deleteok', view1.deleteOkFunc),
# 답글 관련
path('reply', view2.replyFunc),
path('replyok', view2.replyOkFunc),
]
view1.py
from django.shortcuts import render, redirect
from myboard.models import BoardTab
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from datetime import datetime
# Create your views here.
def mainFunc(request):
aa = "<div><h2>게시판 메인</h2></div>"
return render(request, 'boardmain.html', {'msg':aa})
def listFunc(request):
# data_all = BoardTab.objects.all().order_by('-id') # 댓글 코드 X
data_all = BoardTab.objects.all().order_by('-gnum', 'onum') # 댓글 코드 O
paginator = Paginator(data_all, 10)
page = request.GET.get('page')
try:
datas = paginator.page(page)
except PageNotAnInteger:
datas = paginator.page(1)
except EmptyPage:
datas = paginator.page(paginator.num_pages)
return render(request, 'board.html', {'datas':datas})
def insertFunc(request):
return render(request, 'insert.html')
def insertOkFunc(request):
if request.method == 'POST':
try:
gbun = 1 # Group number 구하기
datas = BoardTab.objects.all()
if datas.count() != 0:
gbun = BoardTab.objects.latest('id').id + 1
BoardTab(
name = request.POST.get('name'),
passwd = request.POST.get('passwd'),
mail = request.POST.get('mail'),
title = request.POST.get('title'),
cont = request.POST.get('cont'),
bip = request.META['REMOTE_ADDR'],
bdate = datetime.now(),
readcnt = 0,
gnum = gbun,
onum = 0,
nested = 0
).save()
except Exception as e:
print('insert err : ', e)
return render(request, 'error.html')
return redirect('/board/list') # 추가 후 목록 보기
def searchFunc(request):
if request.method == 'POST':
s_type = request.POST.get('s_type')
s_value = request.POST.get('s_value')
# print(s_type, s_value)
# SQL의 like 연산 --> ORM에서는 __contains=값
if s_type == 'title':
datas_search = BoardTab.objects.filter(title__contains=s_value).order_by('-id')
elif s_type == 'name':
datas_search = BoardTab.objects.filter(name__contains=s_value).order_by('-id')
paginator = Paginator(datas_search, 5)
page = request.GET.get('page')
try:
datas = paginator.page(page)
except PageNotAnInteger:
datas = paginator.page(1)
except EmptyPage:
datas = paginator.page(paginator.num_pages)
return render(request, 'board.html', {'datas':datas})
def contentFunc(request):
page = request.GET.get('page')
data = BoardTab.objects.get(id=request.GET.get('id'))
data.readcnt = data.readcnt + 1 # 조회수 증가
data.save() # 조회수 update
return render(request, 'content.html', {'data_one':data, 'page':page})
def updateFunc(request): # 수정 화면
try:
data = BoardTab.objects.get(id=request.GET.get('id'))
except Exception as e:
return render(request, 'error.html')
return render(request, 'update.html', {'data_one':data})
def updateOkFunc(request): # 수정 처리
try:
upRec = BoardTab.objects.get(id=request.POST.get('id'))
# 비밀번호 비교 후 수정 여부 결정
if upRec.passwd == request.POST.get('up_passwd'):
upRec.name = request.POST.get('name')
upRec.mail = request.POST.get('mail')
upRec.title = request.POST.get('title')
upRec.cont = request.POST.get('cont')
upRec.save()
else:
return render(request, 'update.html', {'data_one':upRec, 'msg':'비밀번호 불일치~'})
except Exception as e:
return render(request, 'error.html')
return redirect('/board/list') # 수정 후 목록 보기
def deleteFunc(request):
try:
del_data = BoardTab.objects.get(id=request.GET.get('id'))
except Exception as e:
return render(request, 'error.html')
return render(request, 'delete.html', {'data_one':del_data})
def deleteOkFunc(request):
del_data = BoardTab.objects.get(id=request.POST.get('id'))
if del_data.passwd == request.POST.get('del_passwd'):
del_data.delete();
return redirect('/board/list') # 삭제 후 목록 보기
else:
return render(request, 'error.html')
view2.py
from django.shortcuts import render, redirect
from myboard.models import BoardTab
from datetime import datetime
# Create your views here.
def replyFunc(request):
try:
data = BoardTab.objects.get(id=request.GET.get('id'))
context = {'data_one':data}
return render(request, 'rep/reply.html', context)
except Exception as e:
print('replyFunc err : ', e)
return render(request, 'error.html')
def replyOkFunc(request):
if request.method == 'POST':
try:
repGnum = int(request.POST.get('gnum'))
repOnum = int(request.POST.get('onum'))
imsiRec = BoardTab.objects.get(id=request.POST.get('id'))
oldGnum = imsiRec.gnum
oldOnum = imsiRec.onum
if oldGnum == repGnum:
oldOnum = oldOnum + 1
# 답글 저장
BoardTab(
name = request.POST.get('name'),
passwd = request.POST.get('passwd'),
mail = request.POST.get('mail'),
title = request.POST.get('title'),
cont = request.POST.get('cont'),
bip = request.META['REMOTE_ADDR'],
bdate = datetime.now(),
readcnt = 0,
gnum = repGnum,
onum = oldOnum,
nested = int(request.POST.get('nested')) + 1
).save()
return redirect('/board/list') # 답글 작성 후 목록 보기
except Exception as e:
print('replyOkFunc err : ', e)
return render(request, 'error.html')
boardmain.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
{{msg | safe}}
메뉴1 분석1 <a href="/board/list">게시판</a>
</body>
</html>
board.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body style="margin: 20px">
<div style="width: 95%; text-align: center;">
<h3>** 게시판 목록 **</h3>
</div>
<a href="/board/insert">글쓰기</a>
<table style="width: 95%" class="table">
<tr>
<th>번호</th><th>제 목</th><th>작성자</th><th>작성일</th><th>조회수</th>
</tr>
{% if datas %}
{% for d in datas %}
<tr>
<td>{{d.id}}</td>
<td>
{% with ''|center:d.nested as range %}
{% for _ in range %}
{% endfor %}
{% endwith %}
<a href="/board/content?id={{d.id}}&page={{datas.number}}">{{d.title}}</a>
</td>
<td>{{d.name}}</td>
<td>{{d.bdate.year}}.{{d.bdate.month}}.{{d.bdate.day}}</td>
<td>{{d.readcnt}}</td>
</tr>
{% endfor %}
<!-- 페이징 처리 -->
<tr>
<td colspan="5" style="text-align: center;">
{% if datas.paginator.num_pages > 1 %}
<div>
{% if datas.has_previous %}
<a href="/board/list?page={{datas.previous_page_number}}">«이전</a>
{% endif %}
{% if datas.has_next %}
<a href="/board/list?page={{datas.next_page_number}}">다음»</a>
{% endif %}
(페이지:{{datas.number}} / {{datas.paginator.num_pages}})
</div>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="5">글이 없어요</td>
</tr>
{% endif %}
<tr>
<td colspan="5" style="text-align: center;">
<form action="/board/search" method="post">{% csrf_token %}
검색 :
<select name="s_type">
<option value="title" selected="selected">글제목</option>
<option value="name">작성자</option>
</select>
<input type="text" name="s_value">
<input type="submit" value="확 인">
</form>
</td>
</tr>
</table>
</body>
</html>
error.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
작업 중 에러 발생!!!
<p/>
<a href="/board/list?page=1">게시판 글 목록</a>
</body>
</html>
insert.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
window.onload = function(){
document.querySelector("#btnOk").onclick = chkFunc;
}
function chkFunc(){
//alert('a');
if(frm.name.value === ""){
alert('작성자를 입력하시오');
frm.name.focus();
return;
}
//나머지는 생략
frm.submit();
}
</script>
</head>
<body style="margin: 20px">
** 새글 입력 **<p/>
<form action="/board/insertok" name="frm" method="post">{% csrf_token %}
<table style="width: 95%" class="table">
<tr>
<td>작성자:</td>
<td><input type="text" name="name" /></td>
</tr>
<tr>
<td>비밀번호:</td>
<td><input type="text" name="passwd" /></td>
</tr>
<tr>
<td>이메일:</td>
<td><input type="email" name="mail" /></td>
</tr>
<tr>
<td>글제목:</td>
<td><input type="text" name="title" style="width: 99%"/></td>
</tr>
<tr>
<td>글내용:</td>
<td>
<textarea rows="5" style="width: 99%" name="cont"></textarea>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center;">
<input type="button" value="등록" id="btnOk" class="btn btn-primary">
</td>
</tr>
</table>
</form>
</body>
</html>
content.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body style="margin: 20px">
<h2>* {{data_one.id}}번 게시글 내용 *</h2>
<table class="table">
<tr style="width: 95%">
<td style="text-align: right; width: 95%">
<a href="/board/reply?id={{data_one.id}}">답글</a>
<a href="/board/update?id={{data_one.id}}">수정</a>
<a href="/board/delete?id={{data_one.id}}">삭제</a>
<a href="/board/list?page={{page}}">목록</a>
</td>
</tr>
</table>
<table class="table">
<tr style="width: 95%;background-color: lightgray">
<td>
작성자 : <a href="mailto:{{data_one.mail}}">{{data_one.name}}</a>
(ip : {{data_one.bip}})
</td>
<td>작성일 : {{data_one.bdate}}</td>
<td>조회수 : {{data_one.readcnt}}</td>
</tr>
<tr>
<td colspan="3">제목 : {{data_one.title}}
</tr>
<tr>
<td colspan="3">
<textarea rows="5" style="width: 99%" readonly="readonly">{{data_one.cont}}</textarea>
</td>
</tr>
</table>
</body>
</html>
update.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
window.onload = function(){
document.querySelector("#btnUpdate").onclick = chkFunc;
}
function chkFunc(){
//alert('a');
if(frm.name.value === ""){
alert('작성자를 입력하시오');
frm.name.focus();
return;
}
//나머지는 생략
frm.submit();
}
</script>
</head>
<body style="margin: 20px">
<h2>* 게시글 수정 *</h2>
<form action="/board/updateok" method="post" name="frm">{%csrf_token%}
<input type="hidden" name="id" value="{{data_one.id}}">
<table style="width: 95%" class="table">
<tr>
<td>작성자:</td>
<td><input type="text" name="name" value="{{data_one.name}}" /></td>
</tr>
<tr>
<td>비밀번호:</td> <!-- 비밀번호를 수정X. 비밀번호를 비교해 맞은 경우 수정이 가능 -->
<td><input type="text" name="up_passwd" />
<span style="color: red">{{msg}}</span>
</td>
</tr>
<tr>
<td>이메일:</td>
<td><input type="email" name="mail" value="{{data_one.mail}}"/></td>
</tr>
<tr>
<td>글제목:</td>
<td><input type="text" name="title" style="width: 99%"
value="{{data_one.title}}"/></td>
</tr>
<tr>
<td>글내용:</td>
<td>
<textarea rows="5" style="width: 99%" name="cont">{{data_one.cont}}</textarea>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center;">
<input type="button" value="수정" id="btnUpdate" class="btn btn-primary">
<input type="button" value="이전" class="btn btn-warning"
onclick="history.back()">
</td>
</tr>
</table>
</form>
</body>
</html>
delete.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
window.onload = function(){
document.querySelector("#btnDel").onclick = delFunc;
document.querySelector("#btnCancel").onclick = cencelFunc;
}
function delFunc(){
// alert("a");
if(document.querySelector("#del_passwd").value === ""){
document.querySelector("#del_passwd").placeholder = "비밀번호 입력";
}else{
let result = confirm("정말 삭제할까요?");
if(result){
document.querySelector("form").submit();
}
}
}
function cencelFunc(){
//alert("b");
history.back();
}
</script>
</head>
<body style="margin: 20px">
<h2>* 게시글 삭제 *</h2>
<form action="/board/deleteok" method="post">{%csrf_token%}
<input type="hidden" name="id" value="{{data_one.id}}">
<table style="width: 95%" class="table">
<tr><th colspan="2">삭제하려면 비밀번호를 입력하세요</th></tr>
<tr>
<td>비밀번호 : </td>
<td><input type="text" name="del_passwd" id="del_passwd"></td>
</tr>
<tr>
<td colspan="2">
<input type="button" value="삭제" id="btnDel">
<input type="button" value="취소" id="btnCancel">
</td>
</tr>
</table>
</form>
</body>
</html>
'Django' 카테고리의 다른 글
django10 - ajax (0) | 2022.10.20 |
---|---|
고객 정보 찾기 예제 (0) | 2022.10.19 |
django project 과정 정리 (0) | 2022.10.18 |
django8 - DB, 표, CRUD, 페이징 (0) | 2022.10.18 |
django7 - DB, multi-table (제조사, 상품 관리) (0) | 2022.10.18 |