Board CRUD 연습
1. board APP 생성
터미널에 django-admin startapp board 입력
* 새 프로젝트를 생성할 때 인터프리터를 제대로 설정하지 않으면 django가 설치되어 있지 않은 경우에 오류가 발생한다!
반드시 새 프로젝트 생성 시 기존에 장고프로젝트에 적용하던 인터프리터를 가져오거나 django를 설치해주어야한다.
2. 프로젝트 폴더에서 settings.py 에서 INSTALLED_APP에 borad 추가
* 문자열 형태로 둘러싸주고 맨뒤에 반드시 (,) 컴마 붙이는 거 잊지 말기
3. 모델생성(DB 설계, DB Table 생성) - model.py에 필요한 컬럼들 생성
models.에 있는 다양한 필드함수라던가, 각각의 Field에 줄 수 있는 인자들 추가 공부 필요!
class BoardModel(models.Model):
title = models.CharField(max_length=50, null=False)
content = models.TextField(null=False)
date = models.DateField(auto_now=True)
create_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
db_table = "board"
4. admin 페이지와 연결 후 마이그레이션 진행하여 잘들어 갔는지 확인
from django.contrib import admin
from .models import BoardModel
# Register your models here.
admin.site.register(BoardModel)
* python manage.py makemigration
-> python manage.py migrate
-> python manage.py createsuperuser 진행 후
127.0.0.0:8000/admin 으로 접속해서 확인 가능
5. board 폴더에 urls.py 생성하고 프로젝트폴더의 urls.py에 path('', includ('board.urls')), 추가로 작성하여 연결
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('board.urls')),
]
* import해온 path 옆에 (,)컴마 찍어서 includ 함수도 추가로 import 해와야함
* includ 함수에 주는 인자는 문자열 형태로 주고 경로를 (/) 가 아닌 (.) 으로 구분해서 작성
* board/urls.py 만들 때 프로젝트의 urls.py 복사해서 붙여넣어 놓고 필요한 내용 채우고 필요없는거 지워서 사용
* 이후 연결할 html 파일들 껍데기만 미리 만들어 두기
6. board/urls.py에서 from board import views 해서 views에 작성한 함수들을 import 해올 수 있도록 하고
path('url', views.만든함수, name='이름') 형태로 작성해서 urls과 views 연결
# board/urls.py
from django.urls import path
from board import views
urlpatterns = [
path('', views.board_list, name='board_list'),
path('board/', views.board_write, name='board_write'),
path('board/<int:pk>', views.board, name='board'),
path('board/update/<int:pk>', views.board_update, name='board_update'),
path('board/delete/<int:pk>', views.board_delete, name='board_delete'),
]
* 한번에 다만들어두면 좋긴하지만 실제로 해보니 한번에 미리 다만들어두기 어렵다.. 한개씩 만들면서 연결하는 게 현실적이다. (위에서 부터 각각 게시글리스트, 글쓰기, 글확인, 글수정, 글삭제)
7. views.py 에서 연결한 각각의 함수들 구현
0) views.py 에 함수들 작성하기전에 필수 import 사항
- 앞서 생성한 모델들을 import 해오기
- 앞으로 사용할 shortcuts에 있는 render, redirect 함수 (HttpResponse도 쓴다면 import 필수)
- 추가로 인증관련 해서는 auth 패키지에 있는 여러함수들을 import 해와야지만 쓸 수 있다.
from django.shortcuts import render, redirect
from .models import BoardModel
1) 게시글 리스트 출력
단순히 게시글들을 화면에 출력만 해주면 되기 때문에 GET방식으로 처리하였고 all()함수를 이용해서 모든 게시글 불러와서 html에 뿌려줄 수 있도록 render 함수 사용
#board/views.py
def board_list(request):
if request.method == "GET":
board_list = BoardModel.objects.all()
return render(request, 'board/board_list.html', {'board_list': board_list})
# templates/board/board_list.html
<table>
<tr>
<th>번호</th>
<th>제목</th>
<th>날짜</th>
</tr>
{% for board in board_list %}
{% csrf_token %}
<tr>
<td>{{ board.pk }}</td>
<td><a href="{% url 'board' board.pk %}">{{ board.title }}</a></td>
<td>{{ board.date }}</td>
</tr>
{% endfor %}
</table>
<a href="{% url 'board_write' %}">글쓰기</a>
2) 게시글쓰기
GET방식으로 요청시에는 글쓰는 페이지로 이동하도록 만들었고 글을 다 작성한 다음 submit하면 POST로 요청하여 작성한 글 내용을 DB에 저장하고 작성한 글을 보여 줄 수 있는 페이지로 이동
form 태그로 POST 방식으로 전달하고 create()함수로 DB에 데이터 저장, {%csrf_token%} 작성 필수 !
# board/views.py
def board_write(request):
if request.method == "GET":
return render(request, 'board/board_write.html')
elif request.method == "POST":
title = request.POST.get('title')
content = request.POST.get('content')
new_board = BoardModel.objects.create(title=title, content=content)
return redirect('board', new_board.pk)
# templates/board/board_write.html
<body>
<form method="post" action="{% url 'board_write' %}">
{% csrf_token %}
<input type="text" id="title" name="title" placeholder="제목">
<textarea id="content" name="content" placeholder="내용"></textarea>
<button type="submit">작성완료</button>
</form>
<a href="{% url 'board_list' %}">목록으로</a>
3) 게시글 확인
함수 인자에 pk를 받아옴으로써 클릭한 해당 게시물에 접근 할 수 있도록 해야함
# board/views.py
def board(request, pk):
if request.method == "GET":
board = BoardModel.objects.get(pk=pk)
return render(request, 'board/board.html', {'board': board})
# templates/board/board.html
<h1>제목 : {{ board.title }}</h1>
<p> 내용 : {{ board.content }}</p>
<a href="{% url 'board_update' board.pk %}">수정</a>
<a href="{% url 'board_delete' board.pk %}">삭제</a>
<a href="{% url 'board_list' %}">목록</a>
4) 게시글 수정
GET 방식으로 요청했을 때 board_update.html에 있는 input, textarea 태그에 해당 게시글의 제목과 내용을 뿌려주기 위해서 클릭한 게시물의 pk를 가져와서 get()함수로 해당 게시물의 정보를 render 로 return하도록 해야함
POST 방식으로 요청했을 경우로는 title과 content를 실제적으로 update를 수행할 때 filter를 pk로 꼭 한번 거친 후에 update 함수를 사용해야한다. 앞서 create와 마찬가지로 POST 요청에서 form 태그안에 {% csrf_token %} 작성
# board/views.py
def board_update(request, pk):
if request.method == "GET":
board = BoardModel.objects.get(pk=pk)
return render(request, 'board/board_update.html', {'board': board})
elif request.method == "POST":
title = request.POST.get('title')
content = request.POST.get('content')
BoardModel.objects.filter(pk=pk).update(title=title, content=content)
return redirect('board', pk)
# templates/board/board_update.html
<form method="post" action="{% url 'board_update' board.pk %}">
{% csrf_token %}
<h3>제목</h3>
<input type="text" id="title" name="title" value="{{ board.title }}">
<h3>내용</h3>
<textarea id="content" name="content">{{ board.content }}</textarea>
<br>
<button type="submit">완료</button>
<a href="{% url 'board_list' %}">목록으로</a>
</form>
5) 게시글 삭제
최초에 POST 형식으로 delete 만들었다가 단순히 a 태그로 버튼 눌렀을 때 연결되도록 했더니
The view board.views.delete_post didn't return an HttpResponse object. It returned None instead.
이러한 오류가 발생되었다. 지금은 단순하게 GET 방식으로 바꾼 것 만으로 문제가 해결이 되었었지만
추후에는 진짜 POST 형식으로 만들때에는 자바스크립트와 연동해서 type에 맞춰서 전송을 해야만한다!
# board/views.py
def board_delete(request, pk):
if request.method == "GET":
BoardModel.objects.filter(pk=pk).delete()
return redirect('/')
# templates/board/board.html
<h1>제목 : {{ board.title }}</h1>
<p> 내용 : {{ board.content }}</p>
<a href="{% url 'board_update' board.pk %}">수정</a>
<a href="{% url 'board_delete' board.pk %}">삭제</a>
<a href="{% url 'board_list' %}">목록</a>
자바스크립트, AJAX를 이용해서 POST 방식으로 삭제 구현
우선 request method 를 POST로 받도록 수정하고
# board/views.py
def board_delete(request, pk):
if request.method == "POST":
BoardModel.objects.filter(pk=pk).delete()
return redirect('/')
먼저 자바스크립트에서 ajax, jquery를 사용하기 위해서 반드시 아래의 한줄이 필요하다!
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
자바스크립트에도 url 입력 시 장고 내장함수를 적용할 수 있어서 간편하게 url을 지정할 수 있다!
# static/board.js
<script>
function delete_board() {
alert('delete_board() 도착')
$.ajax({
type: "POST",
url: '{% url 'board_delete' board.pk %}',
data: {},
success: function (response) {
alert('삭제 완료')
window.location.replace('{% url 'board_list' %}')
}
})
}
</script>
# templates/board/board.html
<h1>제목 : {{ board.title }}</h1>
<p> 내용 : {{ board.content }}</p>
<a href="{% url 'board_update' board.pk %}">수정</a>
<button type="button" onclick="delete_board()">삭제</button>
<a href="{% url 'board_list' %}">목록</a>
보통이라면 이렇게만 했으면 됬을텐데! Django에서는 미들웨어단에서 csrf 공격을 막기위한 보안이 걸려있다! 그래서 csrf 토큰을 생성하고 설정해주어야한다! 설정하지 않고 그냥 실행할 경우 아래와 같이 Forbidden 403 오류가 발생된다!
이를 해결하기 위해선 아래의 코드를 추가할 필요가 있다.
# static/board.js
<script>
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
headers: {"X-CSRFToken": '{{ csrf_token }}'}
});
</script>
위 코드는 django 공식문서에서 제공하는 코드이다. ajax통신할 때 csrf 토큰을 자동으로 생성해주고 저장하도록 ajax의 설정을 셋업해주는 코드이다. 최신버젼에서는 fetch() API를 사용해서 생성 저장 할 수 있는데 아직까지 해당 API 설계도만 보고 사용법을 만들어보기엔 어려워서 우선은 기본적인 django CRUD 연습을 위한 것이기 때문에 fetch API는 추후에 공부해볼 예정이다.
'회고록(TIL&WIL)' 카테고리의 다른 글
TIL2022.06.05 TODAY_LUNCH(요기요 크롤링, csv load-DB 저장) (0) | 2022.06.05 |
---|---|
TIL 2022.06.02 추천시스템 프로젝트 TODAY_LUNCH (S.A) (0) | 2022.06.02 |
TIL 2022.05.30 Django공부 - 회원가입/로그인/로그아웃/로그인유지, csrf_token (0) | 2022.05.30 |
TIL 2022.05.27 Django 공부 - admin, MVT패턴, URL연결, return메서드 (0) | 2022.05.27 |
TIL 2022.05.26 Django 공부 - APP만들기, DB연결, Model생성 (0) | 2022.05.26 |