-
게시판 예제Python Django 2022. 10. 23. 15:17
settings.py
INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "myboard", ] DATABASES = { #리모트(원격) 디비를 걸어놓았다 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'boarddb', #<--- DB명 : db는 미리 작성되어 있어야 함. 'USER': 'root', #<--- 계정명 'PASSWORD': '비밀번호 입력', #<--- 계정 암호 'HOST': '127.0.0.1', #<--- DB가 설치된 컴의 ip 'PORT': '3306', #<--- DBMS의 port 번호 } } LANGUAGE_CODE = "ko-kr" TIME_ZONE = "Asia/Seoul"
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() # ip를 담기 위해 사용 bdate = models.DateTimeField() readcnt = models.IntegerField() gnum = models.IntegerField() # 그룹 넘버(원글 번호와 같음) onum = models.IntegerField() # 원글의 댓글이면 1, 댓글의 댓글이면 2..., nested = models.IntegerField() # 원글의 댓글이면 1, 댓글의 댓글이면 2..., 댓글의 댓글의 댓글이면 3...,
부모 urls.py
from django.contrib import admin from django.urls import path from myboard.views import views1 from django.urls.conf import include urlpatterns = [ path("admin/", admin.site.urls), path("", views1.mainFunc), path("board/", include('myboard.urls')) ]
자식 urls.py
from django.urls import path from myboard.views import views1 urlpatterns = [ path("list", views1.listFunc), path("insert", views1.insertFunc), path("inserOk", views1.inserOkFunc), path("search", views1.searchFunc), # 검색 path("content", views1.contentFunc), # 자세히보기 path("update", views1.updateFunc), path("updateok", views1.updateOkFunc), path("delete", views1.deleteOkFunc), path("deleteok", views1.deleteOkFunc), ]
board.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>
{{msg | safe}} 를 사용해서 html 형식으로 넣어주었다.
board.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" /> </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>{{d.title}}</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>글제목</option> <option value="name" selected>작성자</option> </select> <input type="text" name="s_value"/> <input type="submit" value="확인" /> </form> </td> </tr> </table> </body> </html>
datas의 값들을 반복문 돌려 DB를 분류시킨 뒤, {{}} 태그로 값을 넣어준다.
페이징 처리를 한다. 검색 기능도 넣어준다.
views.py
from django.shortcuts import render from myboard.models import BoardTab from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage # 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 paginator = Paginator(data_all, 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})
페이징 처리를 위해 paginator를 import 하여 사용하였다.
BoardTab DB의 내용을 data_all에 담아 그것을 다시 paginator에 넣어 그 값을 datas에 담아 board.html로 보내준다.
게시글 insert
views.py
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( # table 순서대로 들어가야 된다. 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'], # 클라이언트 컴퓨터 ip를 찾아주는 코드 bdate = datetime.now(), # datetime import 해서 사용 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') # 추가 후 목록 보기
datas에 아무것도 존재하지 않는다면 error.html로 가도록 만든다.
만약 들어있다면 post방식으로 가져온 값들을 넣어주고 그 값들을 save한다.
새로 생성되는 글은 gbun == id값이므로 + 1을 해줘서 만약 id = 8번이면 새로 생성되는 글은 9번으로 생성되게 한다.
redirec 방식으로 /board/list로 보내서 board.html를 출력하게 한다.
error.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <p>작업 중 에러 발생!!!</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 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" /> <script> 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>** 새글 입력 **</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" style="width: 99%" name="title"/></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>
POST 타입으로 값들을 views.py의 insertok 함수로 보낸다.
추가 되면 밑에 lsit가 최신화 된다. redirec 요청
search (검색기능)
views.py
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})
POST값으로 받은 s_value값과, s_type 값을 받은 뒤에 filter를 건 다음 datas_search라는 변수명에 넣은 뒤에 페이징 처리를 하고 그 데이터를 board.html로 보낸다.
board.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" /> </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> <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>글제목</option> <option value="name" selected>작성자</option> </select> <input type="text" name="s_value"/> <input type="submit" value="확인" /> </form> </td> </tr> </table> </body> </html>
select 문을 만들어서 글제목, 작성자 형태로 출력시킨다. 글제목은 title, 작성자는 name으로 만든다.
그것들을 select문의 name으로 s_type으로 만든 뒤, 입력창을 s_value로 지은다음 그것을 /board/search로 보낸다.
조회수 기능(content 게시판 자세히보기)\
views.py
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})
해당 글이 있는 page 번호를 가져온 뒤, 그 아이디 값의 데이터를 가져온다. readcnt가 조회수이기 때문에 해당 글에 들어가게 되면 조회수가 올라가도록 +1을 한다. 그 값을 다시 dict 타입으로 content.html로 가지고 간다.
content.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" /> </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/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}}</td> </tr> <tr> <td colspan="3"> <textarea rows="5" style="width:99%;" readonly>{{data_one.cont}}</textarea> </td> </tr> </table> </body> </html>
board.html에서 content.html로 갈 수 있게 a태그를 사용했다. content.html로 오면 id값으로 데이터를 불러와 그것을 넣어준다. 목록으로 돌아갈 수도 있기때문에 해당 글이 있는 페이지로 갈 수 있도록 page 데이터를 넣어주었다.
글 수정하기
views.py
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') # 수정 후 목록 보기
get 방식으로 받은 id값으로 해당 칼럼의 데이터를 data라는 변수명에 넣고 만약 id 값이 안 넘어오면 error.html 페이지로 이동시키고 들어온다면 그 데이터를 가지고 update.html로 이동시킨다.
update.html에서 post타입으로 보낸 값들을 DB에 넣어줌으로서 수정한다.
그리고 /board/list로 redirect 시킨다.
update.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" /> <script> 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> <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" style="width: 99%" name="title" 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>
id값을 가져오기 위해 input 타입을 hidden으로 주고 post방식으로 다른 값들과 같이 넘겼다.
비밀번호는 수정을 하려는 것이 아닌, 비밀번호를 비교해서 맞은 경우 수정이 가능하도록 할 것이다.
글 삭제하기
views.py
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')
id 값을 가져와서 그것을 다시 deleteOkFunc 로 보내서 id값의 컬럼을 삭제한다.
delete.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" /> <script> window.onload = function(){ document.querySelector("#btnDel").onclick = delFunc; document.querySelector("#btnCancel").onclick = cancelFunc; } 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 cancelFunc(){ // 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>
'Python Django' 카테고리의 다른 글
예제(table 가져와서 join해서 결과 나타내기) (0) 2022.10.23 게시판 예제 - 댓글 (0) 2022.10.23 Python Django 17 - table이 존재하는 상황(table 가져오기) (0) 2022.10.23 Python Django 16 - join 복수의 DB 사용(ORM) (0) 2022.10.23 미니방명록 예제 (0) 2022.10.23