[DjangoCRUD] 장고 RESTful 웹 서비스 구성하기
장고 RESTful 웹 서비스 구성하기
NEW 수정
boards -views.py 코드 수정
# 사용자 입력을 받는 페이지 렌더링
def new(request):
# GET 사용자가 작성할 수 있는 게시글을 달라라는 행위
# POST 사용자가 게시글을 작성하겠다라는 행위
print(request.method) # new.html 에 가면 GET 인지 POST 인지 확인 할 수 있음. GET 임
# GET
if request.method == 'GET':
return render(request, 'boards/new.html')
# POST
else:
print(request.method) # new.html 에 가서 새로 글을 작성하면 GET 인지 POST 인지 확인 할 수 있음. POST 임
title = request.POST.get('title') # 사용자가 POST 로 보낸 걸 get 가져오기
content = request.POST.get('content') # 사용자가 POST 로 보낸 걸 get 가져오기
board = Board(title=title, content=content)
board.save()
return redirect('boards:detail', board.id)
# 위에 new 함수에서 RESTful 처리 했기 때문에 create 함수는 삭제 처리
# # 데이터를 받아서 실제 DB 에 작성
# def create(request):
# title = request.POST.get('title') # 사용자가 POST 로 보낸 걸 get 가져오기
# content = request.POST.get('content') # 사용자가 POST 로 보낸 걸 get 가져오기
# board = Board(title=title, content=content)
# board.save()
# # return redirect(f'/boards/{board.id}/')
# return redirect('boards:detail', board.id)
- boards - templates - boards 폴더 안에 new.html 코드 수정
{% extends 'boards/base.html' %}
{% block body %}
<h1>NEW</h1>
<!--<form action="/boards/create/" method="post">-->
<!--<form action="{# url 'boards:create' #}" method="post">-->
<form action="{% url 'boards:new' %}" method="post"> <!-- RESTful 처리 -->
{% csrf_token %}
<label for="title">Title</label><br />
<input name="title" id="title" type="text" /><br />
<label for="content">Content</label><br />
<textarea name="content" id="content"></textarea><br />
<input type="submit" />
</form>
<!--<a href="/boards/">BACK</a>-->
<a href="{% url 'boards:index' %}">BACK</a>
{% endblock %}
boards - urls.py 코드 수정
from django.urls import path
from . import views
app_name = 'boards'
urlpatterns = [
path('', views.index, name='index'), # www.web.com/boards/
path('new/', views.new, name='new'), # 사용자의 입력을 받아서 게시글을 작성하는 곳
# path('create/', views.create, name='create'), # 사용자가 입력한 데이터를 전송받고 실제 DB에 작성 및 사용자 피드백
path('<int:id>/', views.detail, name='detail'), # www.web.com/boards/<id>/
path('<int:id>/delete/', views.delete, name='delete'),
path('<int:id>/edit/', views.edit, name='edit'), # 게시글 수정 페이지 렌더링
path('<int:id>/update/', views.update, name='update'), # 사용자가 입력한 수정 데이터를 전송 받고 실제 DB 에 수정 후 저장
]
EDIT 추가 수정
boards -views.py 코드 수정
# RESTful 후
# 게시글 수정 페이지 렌더링
def edit(request, id):
# 0. Board 클래스를 통해 id 값에 맞는 데이터를 가져온다.
board = Board.objects.get(id=id) # DRY : Don't repeat yourself
# 1. 사용자의 요청이 GET 인지 POST 인지 확인한다.
if request.method == 'GET':
# 2. GET 요청이면 사용자에게 수정할 페이지를 보여준다.
context = {'board': board}
return render(request, 'boards/edit.html', context)
else:
# 3. POST 요청이면 사용자가 보낸 데이터를 받아서 수정한 뒤 detail page 로 redirect 한다.
title = request.POST.get('title') # 사용자가 POST 로 보낸 걸 get 가져오기
content = request.POST.get('content') # 사용자가 POST 로 보낸 걸 get 가져오기
# id 값에 맞는 board 데이터를 위에서 주어진 title 과 content 에 맞게 수정한 뒤 저장하는 로직
# 해당 데이터의 내용을 주어진 title, content 로 수정한다.
board.title = title
board.content = content
# 저장한다.
board.save()
return redirect('board:detail', id) # 주의! boards:detail 콜론에 띄어쓰기가 있으면 안됨.
# RESTful 전
# def edit(request, id):
# board = Board.objects.get(id=id)
# context = {'board': board}
# return render(request, 'boards/edit.html', context)
# RESTful 전
# def update(request, id):
# title = request.POST.get('title') # 사용자가 POST 로 보낸 걸 get 가져오기
# content = request.POST.get('content') # 사용자가 POST 로 보낸 걸 get 가져오기
# # id 값에 맞는 board 데이터를 위에서 주어진 title 과 content 에 맞게 수정한 뒤 저장하는 로직
# # 1. Board 클래스를 통해 id 값에 맞는 데이터를 가져온다.
# board = Board.objects.get(id=id)
# # 2. 해당 데이터의 내용을 주어진 title, content 로 수정한다.
# board.title = title
# board.content = content
# # 3. 저장한다.
# board.save()
#
# # print(title, content)
# # return redirect(f'/boards/{id}/')
# return redirect('boards:detail', id) # boards:detail 콜론에 띄어쓰기가 있으면 안됨.
boards - templates - boards 폴더 안에 edit.html 코드 수정
{% extends 'boards/base.html' %}
{% block body %}
<h1>EDIT</h1>
<!--<form action="/boards/{{ board.id }}/update/" method="post">-->
<!--<form action="{# url 'boards:update' board.id #}" method="post">-->
<form action="{% url 'boards:edit' board.id %}" method="post"> <!-- RESTful 처리 -->
{% csrf_token %}
<label for="title">Title</label><br />
<input name="title" id="title" type="text" value="{{ board.title }}"/><br /> <!-- value="{{ board.title }} : 기존에 작성한거 보여줌 -->
<label for="content">Content</label><br />
<textarea name="content" id="content">{{ board.content }}</textarea><br />
<input class="btn btn-success" type="submit" value="제출하기" />
</form>
<!--<a href="/boards/">[뒤로가기]</a>-->
<!--<form action="/boards/" method="post">-->
<form action="{% url 'boards:index' %}" method="post">
{% csrf_token %} <!-- 우리 웹 서버에서 어떤 작성이 일어날때는 csrf_token이 필요하다라는 의미 // 보안상 필요 -->
<input class="btn btn-secondary" type="submit" value="뒤로가기"/>
</form>
{% endblock %}
boards - urls.py 코드 수정
from django.urls import path
from . import views
app_name = 'boards'
urlpatterns = [
path('', views.index, name='index'), # www.web.com/boards/
path('new/', views.new, name='new'), # 사용자의 입력을 받아서 게시글을 작성하는 곳
# path('create/', views.create, name='create'), # 사용자가 입력한 데이터를 전송받고 실제 DB에 작성 및 사용자 피드백
path('<int:id>/', views.detail, name='detail'), # www.web.com/boards/<id>/
path('<int:id>/delete/', views.delete, name='delete'),
path('<int:id>/edit/', views.edit, name='edit'), # 게시글 수정 페이지 렌더링
# path('<int:id>/update/', views.update, name='update'), # 사용자가 입력한 수정 데이터를 전송 받고 실제 DB 에 수정 후 저장
]
DELETE 추가 수정
boards - views.py 코드 수정(방법 1)
- http://127.0.0.1:8000/boards/5/delete/ 처리하면 글이 삭제되는 현상이 있음 그러므로 REST 처리를 해서 GET이 아닌 POST 처리하게끔 만든다. 즉 url에 위와 같이 입력해도 삭제가 되지 않는다.
# RESTful 전
def delete(request, id):
board = Board.objects.get(id=id)
board.delete()
# return redirect('/boards/')
return redirect('boards:index') # boards:index 콜론에 띄어쓰기가 있으면 안됨.
# RESTful 후
def delete(request, id):
if request.method == 'GET':
# GET 요청으로 들어오면 detail page 로 다시 redirect
return redirect('boards:detail', id) # boards:detail 콜론에 띄어쓰기가 있으면 안됨.
else:
# POST 요청으로 들어오면 정상 삭제
board = Board.objects.get(id=id)
board.delete()
return redirect('boards:index')
boards -views.py 코드 수정(방법 2)
- POST 만 오게끔 설정 할 수 있다. 그럼 기존 if문을 안써도 된다.
from django.views.decorators.http import require_http_methods
# RESTful 처리 후 # require_http_methods 처리 후
@require_http_methods(['POST'])
# 허락할 것만 리스트에 담는다. ['POST', 'GET'] 이렇게 쓸 수 있음.
# POST 만 오게끔 설정했는데 GET 이 오면 url에 HTTP ERROR 405 뜬다.
# 콘솔창에는 Method Not Allowed (GET): /boards/5/delete/
# [11/Jun/2019 15:27:49] "GET /boards/5/delete/ HTTP/1.1" 405 0 뜬다.
def delete(request, id):
# if request.method == 'GET':
# # GET 요청으로 들어오면 detail page 로 다시 redirect
# return redirect('boards:detail', id) # boards:detail 콜론에 띄어쓰기가 있으면 안됨.
# else:
# POST 요청으로 들어오면 정상 삭제
board = Board.objects.get(id=id)
board.delete()
return redirect('boards:index')
상태 코드(Status Code) 수정
boards - views.py 코드 수정
- 사용자가 홈페이지에 없는 페이지를 입력했을 때 500번 에러가 뜬다. 이럴때 404 에러 뜨게 해야한다. 예를 들면 현재 1번 게시글이 삭제된 상태인데 1번 글을 조회했을 경우. http://127.0.0.1:8000/boards/1/
- 사용자에게 제대로 된? 상태 코드를 보여주는게 좋다.
from django.shortcuts import render, redirect, get_object_or_404
# RESTful 후
# 특정 게시글 하나만 가지고 온다.
def detail(request, id):
# Board 클래스를 사용해서 id 값에 맞는 데이터를 가지고 온다.
# context 로 넘겨서 detail.html 페이지에서 title 과 content 를
# 출력해본다.
board = get_object_or_404(Board, id=id)
context = {'board': board}
return render(request, 'boards/detail.html', context)
html에서 주석 처리 주의 사항
문제
{% extends 'boards/base.html' %}
{% block body %}
<h1>NEW</h1>
<!--<form action="/boards/create/" method="post">-->
<!--<form action="{% url 'boards:create' %}" method="post">-->
<form action="{% url 'boards:new' %}" method="post"> <!-- RESTful 처리 -->
{% csrf_token %}
<label for="title">Title</label><br />
<input name="title" id="title" type="text" /><br />
<label for="content">Content</label><br />
<textarea name="content" id="content"></textarea><br />
<input type="submit" />
</form>
<!--<a href="/boards/">BACK</a>-->
<a href="{% url 'boards:index' %}">BACK</a>
{% endblock %}
정답 : <!--<form action="{# url 'boards:create' #}" method="post">-->
환경
macOS Mojave 10.14.5, python 3.6.8, django 2.2.1, PyCharm CE 2018.3.7.