장고 초급)글 조회와 작성, 수정과 삭제 구현하기(ModelForm, CRUD)

하얀설표 | 작성시간 2024.06.29.

(2024.06.30. 수정됨.)

사용 환경 

OS : Windows 10
python : python 3.10.11
django : Djajgno 5.0.6

주요 파일 경로

blog
|- entry
|  |- views.py
|  |- urls.py
|  |- forms.py
|  |- models.py
|- templates/
   |- post.html

이전 글에서 포스팅을 위한 모델을 작성했으니 이번에는 모델을 통해 글을 작성하고, 수정하고, 삭제하는 작업을 구현해볼 겁니다.
영어권에서 글 작성과 조회, 수정과 삭제는 영어로 Create, Read, Update, Delete라는 단어에서 착안해 CRUD라는 명칭으로 불립니다.

글 조회와 작성 구현하기

글 작성을 위한 폼 생성하기

entry app에 forms.py를 다음과 같이 작성해줍니다.
forms는 관리자 페이지가 아니더라도 model에 데이터를 전달할 수 있도록 해줍니다.

# entry/forms.py
from django import forms
from .models import Post
class Form(forms.ModelForm):
    class Meta:
        model = Post
        fields = '__all__'

글 조회와 작성, 저장 코드 작성하기

글 작성과 작성한 글을 저장하기 위한 post와 save 함수를 작성합니다.

# entry/views.py
from django.http.request import HttpRequest
from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.csrf import csrf_protect
from .models import Post
from .forms import Form
def index(request: HttpRequest):
    ....
# 글 작성 페이지를 구현하는 코드
def post(request: HttpRequest):
    context = {}
    context.update({
        'title': '글 작성하기',
        'form': Form(),
    })
    return render(request, 'post.html', context)
# 작성한 글을 저장하는 코드
@csrf_protect
def save(request: HttpRequest):
    context = {}
    form = Form(data=request.POST)
    if form.is_valid():
        Object: Post = form.save()
        return redirect(f'/entry/{Object.pk}/')
    context.update({
        'title': '글 작성하기',
        'form': form,
    })
    return render(request, 'post.html', context)
# 개별 글 페이지를 만들어주는 코드
def detail(request: HttpRequest, pk: int):
    context = {}
    context.update({
        'object': get_object_or_404(Post, pk=pk),
    })
    return render(request, 'detail.html', context)

get_object_or_404

get_object_or_404는 object를 가져오지 못하면 http 404 응답을 보내는 코드입니다.
다음과 동일한 작업을 합니다.

try: Post.obejct.get(pk=pk)
except: raise {http 404 응답}

redirect

redirect는 단어 그대로 특정 url로 리다이렉트를 수행합니다.

csrf token

{% csrf_token %}은 CSRF 토큰을 뜻합니다.
CSRF란, Cross Site Request Forgery protection의 약자로 사이트 간 요청 위조 공격을 방지하기 위해 사용하는 토큰입니다.
사이트 공격을 방지하기 위해 사용하는 안전장치라고 알아두면 됩니다.

@csrf_protect

전달받은 요청에 포함된 csrf 토큰의 유효성을 검사하는 데코레이터입니다.

url 할당하기

entry app의 urls.py에 글 작성, 저장, 개별 글 페이지 url을 할당해줍니다.
url 끝에 slash(/)를 포함하도록 합니다. 장고는 non-slash url과 slash url을 서로 다른 url로 인식하기 때문입니다.

# entry/urls.py
from django.urls import path
from . import views
urlpatterns = [
    path('', views.index),
    path('post/', views.post), # 글 작성 url
    path('post/save/', views.save), # 글 저장 url
    path('<int:pk>/', views.detail), # 개별 글 페이지 url
]

<int:pk>

개별 글 페이지 url을 보면 url path에 <int:pk>가 사용되었습니다.
이는 detail 함수를 호출할 때, pk라는 arg를 int type으로 전달하겠다는 뜻입니다.

글 작성 페이지에서 사용할 템플릿 작성하기

# templates/post.html
<head></head>
<body>
    <h1>{{ title }}</h1>
    <article>
        <form method="post" action="/entry/{% if not pk %}post/{% else %}{{ pk }}/{% endif %}save/">
            {% csrf_token %}
            {{ form }}
            <input type="submit" value="저장하기">
        </form>
    </article>
</body>

글 조회 페이지 템플릿 만들기

# templates/detail.html
<head></head>
<body>
    <h1>{{ object.title }}</h1>
    <a href="/entry/{{ object.pk }}/edit/">글 수정하기</a>
    <a href="/entry/{{ object.pk }}/delete/">글 삭제하기</a>
    <article>
        <div>
            {{ object.content|safe }}
        </div>
    </article>
</body>

글 작성과 조회해보기(Create, Read)

시험삼아 글을 하나 작성해봅시다.
글을 작성하면 개별 글 페이지로 리다이렉트 하도록 했으니 다음과 같은 화면을 확인할 수 있습니다.

글 목록 페이지를 확인해보면 작성된 글 목록을 확인할 수 있습니다.

글 작성 테스트

글 수정 구현하기

글 수정과 삭제 구현

글 수정과 삭제를 구현하기 위한 코드를 views.py에 추가해줍니다.

# entry/views.py
from django.http.request import HttpRequest
from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.csrf import csrf_protect
from .models import Post
from .forms import Form
def index(request: HttpRequest):
    ...
def post(request: HttpRequest):
    ...
@csrf_protect
def save(request: HttpRequest, pk: int=None):
    context = {}
    form = Form(data=request.POST, instance=get_object_or_404(Post, pk=pk) if pk else None)
    if form.is_valid():
        Object: Post = form.save()
        return redirect(f'/entry/{Object.pk}/')
    context.update({
        'title': '글 작성하기' if not pk else '글 수정하기',
        'form': form,
    })
    return render(request, 'post.html', context)
def detail(request: HttpRequest, pk: int):
    ...
# 글 수정 페이지 코드
def edit(request: HttpRequest, pk: int):
    context = {}
    context.update({
        'title': '글 수정하기',
        'form': Form(instance=get_object_or_404(Post, pk=pk)),
        'pk': pk,
    })
    return render(request, 'post.html', context)
# 글 삭제 코드
def delete(request: HttpRequest, pk: int):
    get_object_or_404(Post, pk=pk).delete()
    return redirect('/entry/')

글 수정 url과 글 삭제 url 할당

다음과 같이 글을 수정하거나 삭제할 때 사용할 url 패턴을 추가합니다.
이전과 마찬가지로 url 끝에 슬래시를 붙여주도록 합니다.

from django.urls import path
from . import views
urlpatterns = [
    path('', views.index),
    path('post/', views.post),
    path('post/save/', views.save),
    path('<int:pk>/', views.detail),
    path('<int:pk>/edit/', views.edit), # 추가
    path('<int:pk>/save/', views.save), # 추가
    path('<int:pk>/delete/', views.delete), # 추가
]

글 수정해보기(Update)

이제 다음과 같이 작성된 포스팅을 수정할 수 있습니다.

글 수정 테스트

글 삭제해보기(Delete)

글을 삭제해봅시다.
앞서 작성한 코드를 그대로 사용하고 있다면 글을 삭제한 다음, 글 목록 페이지로 리다이렉트 됩니다.
.delete() method를 사용하는 경우 db에 저장된 데이터를 삭제하게 됩니다.



이 글의 댓글 기능은 일부러 막아놓았습니다. 궁금한 내용이 있다면 게시판을 이용해주세요!