이번에는 작성한 포스트를 수정하고 삭제하는 기능을 구현해볼 것이다.

우리가 만들었던 Post 모델은 아래와 같다.

class Post(models.Model):
    content = models.CharField(max_length=300, blank=True)
    image = models.ImageField(blank=True, upload_to='posts')
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="posts")
    like_users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="like_posts", blank=True)

네 개의 필드 중 우리가 수정할 필요가 있는 부분은 content와 image 이다. 나머지는 포스트를 작성할 때, 혹은 시간이 지나면서 누군가에 의해 이미 정해진 것이므로 이를 수정할 필요는 없다.

따라서 포스트 작성 시 사용하기 위해 구성했던 PostForm을 그대로 이용하여 포스트를 수정할 수 있다.

1. urls.py 경로 추가

posts 앱 내의 urls.py에 수정, 삭제 요청을 받을 url 경로를 추가한다.

# urls.py
...

urlpatterns = [
    ...
    path('edit/<int:post_id>/', views.edit_post, name="edit_post"),
    path('delete/<int:post_id>/', views.delete_post, name="delete_post"),
]

2. views.py 액션 구성

posts 앱 내의 views.py에 포스트를 수정, 삭제하는 액션을 구성한다.

# views.py
...
from django.views.decorators.http import require_POST

@login_required
def edit_post(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    if post.user == request.user:
        if request.method == 'POST':
            form = PostForm(request.POST, request.FILES, instance=post)
            if form.is_valid():
                form.save()
                return redirect('posts:index')
            return redirect('posts:edit_post')
        else:
            form = PostForm(instance=post)
            return render(request, 'posts/form.html', {'form': form})
    return redirect('posts:index')

@login_required
@require_POST
def delete_post(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    if post.user == request.user:
        post.delete()
    return redirect('posts:index')

instance=post로 PostForm이 가리키는 데이터가 어떤 것인지 지정해줌으로써 그 데이터를 수정할 수 있도록 만든다.

템플릿에 현재 로그인한 유저가 작성한 포스트에만 수정, 삭제할 수 있는 버튼이 보이도록 만들 것이지만 if post.user == request.user 조건문을 이용함으로써 잘못된 경로로 요청이 오는 것을 한 번 더 막고자 했다.

require_POST 데코레이터를 사용하여 POST 요청으로만 삭제가 가능하도록 구현했다.

3. index.html 템플릿 수정

index.html 템플릿에 수정, 삭제 버튼을 추가한다.

<!-- index.html -->
<a href="{% url 'posts:edit_post' post.id %}"><button>수정</button></a>
<form action="{% url 'posts:delete_post' post.id %}" method="POST">
    {% csrf_token %}
    <button type="submit">삭제</button>
</form>

위의 버튼을 적절한 위치에 추가한다.

삭제 버튼의 경우 버튼 한 번 잘못 눌러서 포스트가 삭제될 수 있으므로 모달 등의 컴포넌트를 이용해도 좋다.