본문 바로가기

Django

django9 - DB, 게시판, 댓글

 

 

게시판 예시

댓글 기능 스케치

 

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 %}
  	    	&nbsp;&nbsp;
  	    	{% 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}}">&laquo;이전</a>
  		{% endif %}
  		{% if datas.has_next %}
  			<a href="/board/list?page={{datas.next_page_number}}">다음&raquo;</a>
  		{% endif %}
  		&nbsp;&nbsp;
  		(페이지:{{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">&nbsp;
  		<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