Django를 이용해서 프로젝트를 작성할 때 다음의 순서를 반복적으로 수행하면서 작성했다.
- urls.py 작성
- views.py에 함수 정의
- template 작성
그리고 CRUD를 구현할 때는 R->C->U->D
의 순서로 구현했다. 필자는 보통 관리자 계정으로 데이터를 하나 이상 만들어 놓고 구현한다. 즉, 데이터베이스에 현재 레코드가 몇 개 있는 상태이기 때문에 조회가 잘 되는지 바로 확인이 가능하다. 그래서 R
을 먼저 구현하고 C
와 U
를 구현한다. R
을 구현해 두었기 때문에 이 또한 제대로 수행이 되는지 바로 확인이 가능하다. D
는 다른 기능들에 비해서 필요한 로직이 적기 때문에 마지막에 구현했다.
현재 데이터베이스에는 위 사진과 같이 하나의 레코드가 들어있는 상태이다.
#records/urls.py
from django.urls import path
from . import views
app_name = 'records'
urlpatterns = [
path('', views.index, name='index')
]
도메인서버/record
로 접속하면 조회하는 페이지가 나타나도록 url을 구성했다. 해당 url을 요청하면 views.py
에서 index
라는 함수를 호출한다. 함수 호출을 위해 views
를 import해주어야 한다.
#records/views.py
from .models import Record
def index(request):
def index(request):
records = Record.objects.all()
context = {
'records': records
}
return render(request, 'records/index.html', context)
]
records
에 Django DB API를 이용해서 현재 데이터베이스 내에 모든 QuerySet을 저장한다. 이 때 저장된 형태는 [{QuerySet 객체},...]
의 형태로 리스트 안에 QuerySet이라는 객체가 저장된 형태이다. 이 리스트를 context
라는 객체 데이터에 담아서 index.html
로 넘겨준다.
{% for record in records %}
<h2>운동 일지 목록</h2>
<a href="#">기록하기</a>
<hr>
<h3>운동 일자 : {{ record.date }}</h3>
{% endfor %}
context
객체 데이터 내부에는 records
라는 리스트가 저장되어 있다. index.html
에서는 해당 리스트의 QuerySet을 모두 조회해서 Django Template Language를 이용해서 운동 일자인 data
필드의 데이터를 출력했다.
이제 특정 항목을 자세히 볼 수 있는 페이지를 detail 페이지를 구현할 것이다.
urlpatterns = [
path('', views.index, name='index'),
path('<int:pk>', views.detail, name='detail'),
]
url의 형태가 조금 변했는데, int
형 변수를 url에 담아 정보로 활용한다는 의미이다. views.py
의 함수를 보면 어떻게 활용되는지 알 수 있다.
def detail(request, pk):
record = Record.objects.get(pk=pk)
context = {
'record': record
}
return render(request, 'records/detail.html', context)
url에 담긴 정보가 pk
라는 인수로 전달된다. 특정 pk를 가진 정보만 record
에서 담아서 detail.html
로 넘겨준다.
<h3>운동 일자 : {{ record.date }}</h3>
<p>팔굽혀 펴기 : {{record.push_up}}</p>
<p>턱걸이 : {{record.pull_up}}</p>
index.html
과 마찬가지로 DTL을 이용해서 데이터를 활용한다.
Create는 기록하기
버튼을 눌렀을 때 동작되도록 구현했다. 버튼을 눌렀을 때 기록을 하기 위한 페이지를 랜더링 해주고, 기록을 하고 제출을 하면 데이터베이스에 저장이 된다. 즉, 두 가지 동작을 수행하므로 두 가지 url과 두 가지 views 함수, 두 가지 template가 필요하다. 역시 url을 먼저 등록한다.
urlpatterns = [
path('', views.index, name='index'),
path('<int:pk>', views.detail, name='detail'),
path('new/', views.new, name='new'),
path('create/', views.create, name='create'),
]
new
는 기록하는 페이지를 랜더링하고, create는 데이터베이스에 저장하는 요청이다.
def new(request):
return render(request, 'records/new.html')
new
는 기록하기
버튼을 눌렀을 때 기록 페이지를 랜더링 해준다.
#new.html
<form action="{% url 'records:create' %}">
<label for="date">Date : </label>
<input type="text" id="date" name="date"><br>
<label for="pushup">팔굽혀 펴기 : </label>
<input type="text" id="pushup" name="pushup"><br>
<label for="pullup">턱걸이 : </label>
<input type="text" id="pullup" name="pullup"><br>
<button>저장</button>
<hr>
</form>
form
태그는 사용자의 입력 정보를 submit
처리 해주기 위해서 필수적으로 사용해야하는 태그이다. form
태그 내부의 정보를 제출하면 views.py
의 create
함수의 request
로 전달된다.
def create(request):
date = request.GET.get('date')
push_up = request.GET.get('push_up')
pull_up = request.GET.get('pull_up')
record = Record(date=date, push_up=push_up, pull_up=pull_up)
record.save()
return redirect('records:detail', record.pk)
데이터를 받아서 record
인스턴스로 생성한 뒤 저장하면 데이터 베이스에 기록된다. 그리고 detail
로 redirect
해서 detail
함수가 다시 동작하도록 한다. 여기서 render
가 아닌 redirect
를 실행하는 이유는 변경 사항을 적용시킨 후에 페이지를 랜더링하기 위함이다.
update는 detail
페이지에서 수정
버튼을 눌러서 동작하도록 구현했다. update도 create와 마찬가지로 수정 페이지를 랜더링하는 것과 데이터베이스에 저장하는 두 가지 동작을 수행하도록 구현했다.
전반적으로 이미 create에서 나온 내용이거나 같은 부분이어서 update에 대한 자세한 내용은 생략.
차이점은 views.py
에서 함수를 정의할 때 create에서는 새로운 객체 인스턴스를 만들어서 데이터를 할당했다면, update에서는 기존에 있던 데이터를 담은 인스턴스를 만들어서 값을 할당했다는 점이다.
def delete(request, pk):
record = Record.objects.get(pk=pk)
record.delete()
return redirect('records:index')
delete는 비교적 로직이 간단하다. pk에 맞는 데이터를 찾아서 삭제하면 된다.