참고문서


현재는 comment_create후 무조건 post_list뷰로 이동한다. 하지만 댓글은 post_listpost_detail양쪽에서 작성할 수 있으므로, 댓글 작성 후 요청을 보낸 위치로 리다이렉트되도록 뷰를 수정한다.

이 때, 돌아갈 위치는 URL의 GET파라미터를 사용하며, 키는 next를 사용한다.

post_list.html에서 각 Post를 HTML상에서 구분할 수 있도록 템플릿에서 id값 추가, include할 post.html에 post_type변수 값 전달

templates/post/post_list.html

{% extends 'base.html' %}

{% block title %}Post List{% endblock %}
{% block content %}
<div class="row">
	{% for post in posts %}
		<div id="post-{{ post.pk }}">
			{% include 'include/post.html' with post_type='list' %}
		</div>
	{% endfor %}
</div>
{% endblock %}

Post를 HTML상에서 구분할 수 있도록 for loop마다 post-<pk>에 해당하는 id속성값을 할당하며, post_type변수의 값을 list로 지정한다. post_type변수의 뜻은 아래 post.html에 대한 설명에서 참고한다.

post_detail.html에서 include할 post.html에 post_type변수 값 전달

templates/post/post_detail.html

{% extends 'base.html' %}

{% block title %}Post Detail{% endblock %}
{% block content %}
<div>
	{% include 'include/post.html' with post_type='detail' %}
</div>
{% endblock %}

post_type변수의 값을 detail로 지정한다. post_type변수의 뜻은 아래 post.html에 대한 설명에서 참고한다.

post.html의 form action에 next값을 할당

templates/include/post.html

<form
	action="{% url 'post:comment_create' post_pk=post.pk %}?next=
	{% if post_type == 'list' %}
		{% url 'post:post_list' %}#post-{{ post.pk }}
	{% elif post_type == 'detail' %}
		{% url 'post:post_detail' post_pk=post.pk %}
	{% endif %}"
	method="POST"
	class="comment-form">
	{% csrf_token %}
	{{ comment_form.content }}
</form>

아래의 CommentForm에 해당하는 부분을 수정한다.

post_type이라는 변수를 받아서 next값을 다르게 할당한다.
post_type변수의 값이post_list일 경우 post:post_list url에 해당하는 목록 페이지에서 해당 Post로 이동할 수 있는 id값에 해당하는 앵커 링크 주소를 넣어주며, post_detail의 경우엔 상세 페이지로 갈 수 있는 post:post_detail url을 생성한다.

comment_create 뷰 수정

post/views.py

def comment_create(request, post_pk):
    # GET파라미터로 전달된 작업 완료 후 이동할 URL값
    next_path = request.GET.get('next')

    # 요청 메서드가 POST방식 일 때만 처리
    if request.method == 'POST':
        # Post인스턴스를 가져오거나 404 Response를 돌려줌
        post = get_object_or_404(Post, pk=post_pk)
        # request.POST데이터를 이용한 Bounded Form생성
        comment_form = CommentForm(request.POST)
        # 올바른 데이터가 Form인스턴스에 바인딩 되어있는지 유효성 검사
        if comment_form.is_valid():
            # 유효성 검사에 통과하면 ModelForm의 save()호출로 인스턴스 생성
            # DB에 저장하지 않고 인스턴스만 생성하기 위해 commit=False옵션 지정
            comment = comment_form.save(commit=False)
            # CommentForm에 지정되지 않았으나 필수요소인 author와 post속성을 지정
            comment.post = post
            comment.author = request.user
            # DB에 저장
            comment.save()

            # 성공 메시지를 다음 request의 결과로 전달하도록 지정
            messages.success(request, '댓글이 등록되었습니다')
        else:
            # 유효성 검사에 실패한 경우
            # 에러 목록을 순회하며 에러메시지를 작성, messages의 error레벨로 추가
            error_msg = '댓글 등록에 실패했습니다\n{}'.format(
                '\n'.join(
                    [f'- {error}'
                     for key, value in comment_form.errors.items()
                     for error in value]))
            messages.error(request, error_msg)
        
        # next parameter에 값이 담겨 온 경우, 해당 경로로 이동
        if next_path:
            return redirect(next_path)
        # next parameter가 빈 경우 post_list뷰로 이동
        return redirect('post:post_list')