Django - CRUD 구현

Django를 이용해서 프로젝트를 작성할 때 다음의 순서를 반복적으로 수행하면서 작성했다.

  1. urls.py 작성
  2. views.py에 함수 정의
  3. template 작성

그리고 CRUD를 구현할 때는 R->C->U->D의 순서로 구현했다. 필자는 보통 관리자 계정으로 데이터를 하나 이상 만들어 놓고 구현한다. 즉, 데이터베이스에 현재 레코드가 몇 개 있는 상태이기 때문에 조회가 잘 되는지 바로 확인이 가능하다. 그래서 R을 먼저 구현하고 CU를 구현한다. R을 구현해 두었기 때문에 이 또한 제대로 수행이 되는지 바로 확인이 가능하다. D는 다른 기능들에 비해서 필요한 로직이 적기 때문에 마지막에 구현했다.

1. Read 구현

현재 데이터베이스에는 위 사진과 같이 하나의 레코드가 들어있는 상태이다.

#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필드의 데이터를 출력했다.

DTL 참고

이제 특정 항목을 자세히 볼 수 있는 페이지를 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을 이용해서 데이터를 활용한다.

2. Create 구현

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.pycreate함수의 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인스턴스로 생성한 뒤 저장하면 데이터 베이스에 기록된다. 그리고 detailredirect해서 detail함수가 다시 동작하도록 한다. 여기서 render가 아닌 redirect를 실행하는 이유는 변경 사항을 적용시킨 후에 페이지를 랜더링하기 위함이다.

3. Update 구현

update는 detail페이지에서 수정 버튼을 눌러서 동작하도록 구현했다. update도 create와 마찬가지로 수정 페이지를 랜더링하는 것과 데이터베이스에 저장하는 두 가지 동작을 수행하도록 구현했다.

전반적으로 이미 create에서 나온 내용이거나 같은 부분이어서 update에 대한 자세한 내용은 생략.

차이점은 views.py에서 함수를 정의할 때 create에서는 새로운 객체 인스턴스를 만들어서 데이터를 할당했다면, update에서는 기존에 있던 데이터를 담은 인스턴스를 만들어서 값을 할당했다는 점이다.


4. Delete 구현

def delete(request, pk):
    record = Record.objects.get(pk=pk)
    record.delete()
    return redirect('records:index')

delete는 비교적 로직이 간단하다. pk에 맞는 데이터를 찾아서 삭제하면 된다.

좋은 웹페이지 즐겨찾기