GET과 POST
HTTP Method, 즉 HTTP 프로토콜을 통해서 서버에 값을 전달할 때 사용하는 방식의 종류, 이 외에 다른 방식들도 있음
하나의 URL에 요청을 보낼 때 GET과 POST 방식을 모두 사용할 수 있음, 방식을 기준으로 분기를 나누어 처리하면 됨
GET
- URL에 파라미터 값으로 데이터를 전달 → URL에 파라미터가 보여짐, 비교적 보안이 취약함
- 캐시가 남고 브라우저의 히스토리에 파라미터 정보가 저장되어 비교적 속도가 빠름
- 주로 조회(Read)에 많이 사용, 데이터를 변경하지 않음
?[key1]:[value1]&[key2]:[value2]&...
와 같은 형식
- ex) https://www.google.com/search ?q=%EA%B2%80%EC%83%89&oq=%EA%B2%80%EC%83%89&aqs=chrome..69i57j69i59j69i61l3.581j0j7&sourceid=chrome&ie=UTF-8
POST
- Request Body에 데이터를 넣어서 전달 → URL에 파라미터가 보여지지 않음, 비교적 안전함(SSL 사용 시 더욱 안전함)
- 캐시 및 파라미터 정보가 남지 않고 비교적 속도가 느림
- 주로 입력(Create), 수정(Update), 삭제(Delete)에 많이 사용, 데이터를 변경함
- URL에 정보를 담을 수 있는 한계를 초과하거나, 바이너리 데이터와 같은 파일 업로드를 처리하는 경우 사용
CRUD 구현
Create
폼으로 입력받은 데이터를 DB에 저장 후 다시 index 페이지로 이동
# myapp/views.py
from django.shortcuts import render, redirect
from .models import Memo
def index(request):
return render(request, 'index.html')
def createMemo(request):
# POST 요청으로 받은 데이터 중 text라는 이름으로 넘어온 데이터를 text라는 이름의 변수에 저장
text = request.POST['text']
# Memo 테이블의 text 필드에 text 변수의 값을 넣어 레코드 생성 후 해당 레코드를 memo라는 이름의 변수에 저장
memo = Memo(text=text)
# 생성한 레코드를 DB에 저장
memo.save()
# 지정한 페이지로 이동, 주소를 직접 지정하거나 urls.py에서 지정한 name 값을 적어줌
return redirect('index') # = HttpResponseRedirect(reverse('index'))
Read
DB에서 데이터 조회 후 템플릿에 전달
- 모든 모델 클래스는
objects
를 가짐
all()
: 해당 모델 클래스, 즉 테이블의 모든 레코드를 반환
# myapp/views.py
...
def index(request):
# DB에서 Memo 테이블의 모든 글을 가져옴
memos = Memo.objects.all()
# 템플릿에 전달하기 위해 데이터를 딕셔너리 타입의 context 변수에 추가, 반드시 딕셔너리 타입이어야 함
context = {'memos': memos}
# 데이터를 포함하여 템플릿 렌더링
return render(request, 'index.html', context)
...
템플릿에서 데이터를 리스트로 표시
<!-- myapp/templates/index.html -->
<!-- 이전에 생성한 form 태그 아래에 추가 -->
...
<div>
<ul>
{% for memo in memos %}
<li>
#{{ memo.id }} [{{ memo.created_at | date:'Y-m-d' }}] {{ memo.text }}
</li>
{% endfor %}
</ul>
</div>
...
Update
urls.py에 수정 경로 추가
- Dynamic URL: 요청 시 URL에 전달되는 파라미터 값을 변수로 사용하여 페이지를 렌더링,
<[타입]:[변수명]>
형태로 작성
# myapp/urls.py
# 이전에 생성한 urlpatterns에 경로 추가
...
urlpatterns = [
...,
path('update/<str:id>/', views.updateMemo, name='updateMemo'),
]
views.py에 updateMemo 함수 추가
- Dynamic URL로 전달받은 변수가 request와 함께 함수의 입력값으로 전달됨
get()
: 해당 모델 클래스, 즉 테이블에서 필드 값이 지정한 값과 같은 레코드 하나만 반환 → 존재하지 않거나 둘 이상인 경우 에러 발생
# myapp/views.py
...
def updateMemo(request, id):
# URL로 전달받은 id와 같은 id를 가진 Memo 테이블의 레코드를 찾아 memo 변수에 저장
memo = Memo.objects.get(id=id)
# GET 요청이라면, 즉 수정 페이지를 표시하라는 요청이라면
# context에 레코드를 담아 템플릿에 전달
if request.method == 'GET':
context = {'memo': memo}
return render(request, 'update.html', context)
# POST 요청이라면, 즉 수정한 내용이 포함된 요청이라면
# 전달 받은 text로 레코드의 text 필드 값을 대체하여 DB에 저장 후 path의 name이 index인 페이지로 이동
elif request.method == 'POST':
memo.text = request.POST['text']
memo.save()
return redirect('index')
...
템플릿에 수정 페이지로 이동하는 링크 생성
<!-- myapp/templates/index.html -->
<!-- 이전에 생성한 리스트 항목에 링크 추가 -->
...
<div>
<ul>
{% for memo in memos %}
<li>
#{{ memo.id }} [{{ memo.created_at | date:'Y-m-d' }}] {{ memo.text }}
<a href="./update/{{ memo.id }}/">[ 수정 ]</a>
</li>
{% endfor %}
</ul>
</div>
...
수정 페이지로 사용할 템플릿 생성
<!-- myapp/templates/update.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Update Memo</title>
<style>
form > label {
display: inline-block;
width: 120px;
}
form > input {
padding: 4px;
margin-bottom: 4px;
}
</style>
</head>
<body>
<h1>Memo Form</h1>
<form action="#" method="POST" id="updateMemoForm">
{% csrf_token %}
<label for="text">메모 수정</label>
<input
type="text"
id="text"
name="text"
autocomplete="off"
placeholder="내용을 입력하세요."
value="{{ memo.text }}"
/>
</form>
<button type="submit" form="updateMemoForm">완료</button>
</body>
</html>
Delete
urls.py에 삭제 경로 추가
# myapp/urls.py
# 이전에 생성한 urlpatterns에 경로 추가
...
urlpatterns = [
...,
path('delete/<str:id>/', views.deleteMemo, name='deleteMemo'),
]
views.py에 deleteMemo 함수 추가
delete()
: 해당 레코드를 DB에서 삭제
# myapp/views.py
...
def deleteMemo(request, id):
# URL로 전달받은 id와 같은 id를 가진 Memo 테이블의 레코드를 찾아 memo 변수에 저장
memo = Memo.objects.get(id=id)
# 해당 레코드를 DB에서 삭제
memo.delete()
# path의 name이 index인 페이지로 이동
return redirect('index')
...
템플릿에 삭제 요청을 보내는 링크 생성
<!-- myapp/templates/index.html -->
<!-- 이전에 생성한 리스트 항목에 링크 추가 -->
...
<div>
<ul>
{% for memo in memos %}
<li>
#{{ memo.id }} [{{ memo.created_at | date:'Y-m-d' }}] {{ memo.text }}
<a href="./update/{{ memo.id }}/">[ 수정 ]</a> |
<a href="./delete/{{ memo.id }}/">[ 삭제 ]</a>
</li>
{% endfor %}
</ul>
</div>
...
참고: 하나의 URL에서 GET과 POST를 모두 처리하는 방법
def test(request):
if request.method == 'GET':
# GET 방식으로 요청한 경우 수행할 작업
elif request.method == 'POST:
# POST 방식으로 요청한 경우 수행할 작업
※ 강의 링크: https://inf.run/DmuA