Development/Django
[Django 프레임워크 제대로 배우기] 3. CRUD 구현
조코링
2023. 1. 29. 17:13
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) ...
- 모든 모델 클래스는
템플릿에서 데이터를 리스트로 표시
{% %}
: for, if, csrf_token 등 템플릿 태그, 빌트인 태그 공식 문서 참고{{ }}
: 변수|[필터 이름]:[필요 시 값 지정]
: 길이, 날짜 형식 등 필터, 빌트인 필터 공식 문서 참고
<!-- 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'), ]
- Dynamic URL: 요청 시 URL에 전달되는 파라미터 값을 변수로 사용하여 페이지를 렌더링,
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를 모두 처리하는 방법
- view 함수에서 분기 처리
def test(request):
if request.method == 'GET':
# GET 방식으로 요청한 경우 수행할 작업
elif request.method == 'POST:
# POST 방식으로 요청한 경우 수행할 작업
※ 강의 링크: https://inf.run/DmuA