// api.js
// 하트를 누르면 실행되는 좋아요 함수
async function likeClick() {
const urlParams = new URLSearchParams(window.location.search);
const postId = urlParams.get("post_id");
const response_post = await getPost(postId);
let token = localStorage.getItem("access")
const response = await fetch(`${backend_base_url}/posts/${postId}/likes/`, {
method: 'POST',
headers: {
"Authorization": `Bearer ${token}`
},
})
location.reload()
}
// post_detail.js
// 게시글 상세페이지로 들어왔을 때 로드되는 동작 함수
window.onload = async function () {
const urlParams = new URLSearchParams(window.location.search);
const postId = urlParams.get("post_id");
const response = await getPost(postId);
...
// 좋아요 개수 보이기
const count = document.getElementById("count")
count.innerText = `좋아요 ${response.like.length}개`
...
await loadPosts(postId);
await loadComments(postId);
}
현재는 payload에서 유저 정보를 받아와서 팔로잉 상태와 좋아요 개수를 로드한다
<좋아요 비동기방식으로 구현>
- 백엔드에서 유저 정보 조회 시 좋아요 한 게시글 같이 출력하기
현재 백엔드에는 유저 정보 조회 시 id, username, email, name, age, introduction, follwings 필드만 나온다
# users/serializers.py
...
class UserProfileSerializer(serializers.ModelSerializer):
followings = serializers.StringRelatedField(many=True)
class Meta:
model = User
fields = ['id', 'username', 'email', 'name', 'age', 'introduction', 'followings']
여기에 유저가 좋아한 게시글을 추가해보자
게시글 모델에는 like라는 유저 모델과 ManyToMany 관계를 가지는 필드가 있다
related_name은 like_posts로 설정되어 있다
like_posts 필드를 시리얼라이저에 추가해보자
# users/serializers.py
...
class UserProfileSerializer(serializers.ModelSerializer):
followings = serializers.StringRelatedField(many=True)
like_posts = serializers.SerializerMethodField()
def get_like_posts(self, obj):
return obj.user.like_posts
class Meta:
model = User
fields = ['id', 'username', 'email', 'name', 'age', 'introduction', 'followings', 'like_posts']
이렇게 하면 에러가 뜬다
AttributeError: 'User' object has no attribute 'user'
get_like_posts 함수의 return 값으로 obj 다음 user로 접근하는 게 아닌 것 같다
실제로 User 모델엔 user 필드가 없다 ㅋㅋ
# users/serializers.py
...
def get_like_posts(self, obj):
return obj.like_posts
...
# 에러 출력
# TypeError: Object of type ManyRelatedManager is not JSON serializable
원래는 이렇게 백엔드의 좋아요 기능과 연동하고 location.reload()를 써서 새로고침 되면 좋아요 개수가 올라가게끔 했다(좋아요 개수 올라가는 함수는 post_detail.js 쪽에 있다
이 함수는 새로고침 여부와 관계없이 좋아요 기능이 실행된다
하지만 새로고침 하지 않으면 좋아요 개수가 변경된 걸 확인할 수 없다
// api.js
// 좋아요 누르기
async function likeClick() {
const urlParams = new URLSearchParams(window.location.search);
const postId = urlParams.get("post_id");
const post = await getPost(postId);
let token = localStorage.getItem("access")
let clickLike = document.getElementById("like")
let clickDislike = document.getElementById("dislike")
const response = await fetch(`${backend_base_url}/posts/${postId}/likes/`, {
method: 'POST',
headers: {
"Authorization": `Bearer ${token}`
},
})
const response_json = await response.json()
//좋아요 하트 색 및 개수 변경
if (response_json == "like") {
clickLike.setAttribute("style", "display:flex;")
clickDislike.setAttribute("style", "display:none;")
count.innerText = `좋아요 ${post.like.length + 1}개`
} else if (response_json == "dislike") {
clickLike.setAttribute("style", "display:none;")
clickDislike.setAttribute("style", "display:flex;")
count.innerText = `좋아요 ${post.like.length - 1}개`
}
}
이 함수를 완성하기까지 여러 시행착오를 겪었다
그 중간과정이 너무 길어서 생략한다...
주요 이슈로는 좋아요 1번 누르면 좋아요 개수가 안 바뀌고 한 번 더 누르면 그때부터 바뀌는 것, 좋아요 누르면 개수는 비동기로 변경되는데 하트는 변경되지 않는 것, 하트는 빨개지는데 좋아요 개수는 줄어드는 것 등이 있었다 ㅋㅋ
일단 좋아요 기능이 동작하려면 post_id가 있어야 하므로 현재 주소창에서 post_id를 받아와서 getPost()함수를 실행한다
좋아요 기능은 상세페이지에만 있으므로 좋아요 버튼을 누를 때 현재 주소창에 항상 post_id가 있다(만약 게시글 목록에서 좋아요 버튼을 누를 수 있게 하려면 또 다른 방법을 써야할 것이다)
헤더에 유저 정보를 담기 위해 token을 받아온다
post_detail.html에 좋아요 버튼 부분을 id를 이용해서 선택한다
fetch를 통해 좋아요 기능이 실행되고, 돌아온 response를 이용해서 하트 색깔을 바꾼다
원래는 백엔드 response에 좋아요, 좋아요 취소가 담겨 있었는데 편의상 like, dislike로 변경했다
# posts.views.py
...
class PostLikesView(APIView):
def post(self, request, post_id):
"""게시글 좋아요 누르기"""
post = get_object_or_404(Post, id=post_id)
if request.user in post.like.all():
post.like.remove(request.user)
return Response("좋아요 취소", status=status.HTTP_200_OK)
else:
post.like.add(request.user)
return Response("좋아요", status=status.HTTP_200_OK)
...
# 아래로 수정
...
class PostLikesView(APIView):
def post(self, request, post_id):
"""게시글 좋아요 누르기"""
post = get_object_or_404(Post, id=post_id)
if request.user in post.like.all():
post.like.remove(request.user)
return Response("dislike", status=status.HTTP_200_OK)
else:
post.like.add(request.user)
return Response("like", status=status.HTTP_200_OK)
나중에 following 기능도 비동기 방식으로 바꾼다면 백엔드 response를 follow, unfollow로 바꾸면 좋을 것 같다 지금은follow 했습니다, unfollow 했습니다로 써있는데 편의상...! 그냥 한 단어로 response 값을 보내는 게 좋을 듯!
여튼 response가 lilke라면 좋아요를 클릭한 것이므로 빨간 하트를 display: flex로 바꿔서 보이게 하고 빈 하트를 none로 바꿔서 안 보이게 한다
좋아요 개수를 바꾸는 부분은 현재 post.like.length로 좋아요 개수를 알 수 있는데 좋아요를 클릭했을 때 이게 업데이트 되지 않는다 새로고침 하거나 클릭을 여러 번 해야 좋아요 개수가 변경되는 오류가 있다
아마도 새로고침을 안 해서 post 오브젝트에 그 값이 전달이 안 돼서 그런 것 같다
이 부분은 보여지기만 하는 부분이므로 좋아요 한 경우에는 현재 값에서 +1, 좋아요 취소 한 경우에는 현재 값에서 -1이 되도록 했다
html에는 좋아요 개수 부분에 Text 값은 없다(있으면 페이지 접속했을 때 기본 값이 보여서 혼란을 야기한다 없는 게 낫다)