[Django / 블로그] Ajax를 이용한 댓글 업데이트
기존에는 포스트에 댓글을 작성했을 때 댓글을 생성하고, 업데이트 된 댓글을 보여주기 위해서 해당 포스트로 리다이렉트를 해줬다.
이 방식은 웹 페이지 전체를 로딩하므로 다시 로드가 필요없는 포스트 내용까지 로드하게 되었는데,내가 원하는 건 단지 ‘댓글’ 부분만 재갱신하는 것이기 때문에 이를 구현할 수 있는 방법을 찾아보았고, Ajax란 기법을 알게되었다
fetch api
javascript가 제공하는 fetch api를 통해 Ajax를 구현할 수 있다. fetch 메서드는 첫 번째 인자로 URL, 두 번째 인자로 옵션 객체를 받고 Promise 타입의 객체를 반환한다.
GET Request
fetch는 기본 값이 GET방식으로 설정되어있다. 일단 간단한 GET 방식의 예시를 보자
fetch('<http://example.com/movies.json>')
.then((response) => response.json())
.then((data) => console.log(data));
첫 번째 인자는 요청을 할 URL를 받는다. 이 요청에서 받은 응답 객체는 json()이란 매서드를 제공하는데 호출 시 JSON 본문 콘텐츠를 추출할 수 있다. 또한 추출한 데이터를 Promise 형태로 반환한다.
나는 댓글들의 데이터를 가져올 뿐만 아니라 생성을 위해 데이터를 전송해야하기 때문에 POST 방식을 알아야했다.
POST Request
fetch(URL, {
method: 'POST',
credentials: 'same-origin',
headers:{
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify({'comment_data':'comment data'})
})
.then(response => {
return response.json() //Convert response to JSON
})
.then(data => {
console.log(data);
})
두 번째 인자로 옵션 객체가 있는 것을 볼 수 있는데, HTTP 방식, HTTP 요청 헤더, HTTP 요청 전문등을 설정할 수 있다.
이전에 말했듯이 fetch는 디폴트가 GET으로 설정되어 있기 때문에 method 옵션을 POST로 지정해야한다.
credentials 옵션의 ‘same-origin’은 요청 URL이 스크립트와 같은 출처일 때만 자격증명을 전송한다. 만약 전송하지 않도록 하려면 ‘omit’을 사용하면 된다.
다음은 헤더로, 댓글의 데이터를 JSON포멧으로 전송할 것이기 때문에 Accept 헤더를 ‘application/json’ 으로 설정했고, view에서 이 요청이 ajax요청인지 구분 할 수 있도록 해주기 위해 'X-Requested-With'헤더를 'XMLHttpRequest'로 세팅했다.
django에서 POST방식을 사용할 땐, csrf 토큰이 반드시 포함되어야한다. 따라서 'X-CSRFToken’ 헤더는 반드시 포함되어야고 여기서의 csrf 토큰은 django 문서에 얻을 수 있는 방법을 제공한다.
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
body에는 보낼 데이터를 포함한다. JSON 포멧으로 전달할 것이라 설정했으므로 객체를 JSON 문자열로 변환해서 body 옵션에 설정해준다.
이제 간단하게 사용법을 알았으니 구현을 해보자.
function summitComment(comment, user_pk, post_pk){
URL = document.URL + 'new-comment/';
fetch(URL,
{
method: 'POST',
credentials: 'same-origin',
headers:{
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': csrftoken
},
body: JSON.stringify({
'comment': comment,
'user_pk': user_pk,
'post_pk': post_pk
}),
},
).then(response => {
return response.json();
}).then(data => {
updateCommentList(data)
});
}
댓글의 내용, 댓글을 쓴 유저와 댓글이 쓰인 포스트의 정보를 함께 전송한다.
from django.http import JsonResponse
import json
def new_comment(request):
if request.headers.get('x-requested-with') == 'XMLHttpRequest':
comment_info = json.load(request)
post = get_object_or_404(Post, pk=comment_info['post_pk'])
user = get_object_or_404(User, pk=comment_info['user_pk'])
comment_content = comment_info['comment']
Comment.objects.create(
author=user,
post=post,
content=comment_content,
)
data = {
'comments': [
{
'author': comment.author.username,
'content': comment.content,
'pub_date': comment.get_pub_date(),
'comment_pk': comment.pk,
'author_pk': comment.author.pk,
'post_pk': post.pk
} for comment in post.comment_set.all()]
}
return JsonResponse(data)
else:
raise PermissionDenied
ajax 요청일 때만 댓글을 생성하기 위해 'X-Requested-With' 헤더에 'XMLHttpRequest'로 설정해주었고 이를 이용해서 구분을 해주었다.
댓글을 생성하고 이제 업데이트된 포스트의 댓글들을 가져와야한다. 따라서 해당 포스트의 댓글들의 정보를 딕셔너리에 담고, JsonResponse
를 이용해서 데이터를 JSON 응답으로 클라이언트에 전달한다.
이렇게 받은 댓글 데이터들을 이용해서 댓글 리스트 부분만 재갱신 해주면 성공이다.
성공!
Delete Comment