본문 바로가기
source-code/Django

Blogs App _ 좋아요 기능

by mattew4483 2021. 1. 10.
728x90
반응형

똑같은 글을 써도, 다른 사람들이 많이 읽고 관심을 가져주면 더 의욕이 생기는 법.

이를 측정(?) 하기 위해 좋아요 기능을 구현해보자.


1. model 수정

좋아요 기능을 구현하기 위해서는... 이 녀석의 정체부터 알아야 한다!

좋아요란 뭘까? 기본적으로 좋아요는 각 게시글에 달리는 개념이다.

즉, Post라는 모델 안에 있는 속성 중 하나로 좋아요 를 추가해주면 될 테다.

 

또한 좋아요는 게시글과 유저와의 관계이기도 하다.

하나의 게시글은 여러 개의 좋아요를 가질 수 있고,

한 명의 유저는 여러 개의 게시글에 좋아요를 누를 수 있다.

→ 이런 속성의 field 이름은??? 바로 바로 ManyToManyField !

 

마지막으로 좋아요 횟수는 게시글과 유저와의 관계이지 단독적인 횟수를 의미하는 게 아니다!

즉 단순히 몇 회 가 아닌, 해당 게시글에 좋아요를 누른 유저의 총합이 바로 좋아요 가 되는 것!!!

 

models.py

그래서 야무지게 썼다!

ManyToManyField는 models.ManyToManyField('참조할 모델') ← 이런 식으로 적어주면 된다.

 

야무지게 makemigrations를 진행했다!

에러가 떴다!!! 따란.

 

무슨 소린고... 하고 찬찬히 읽어보자.

Reverse accessor for 'Post.likes' clashes with reverse accesoor for 'Post.owner'

Post 모델의 likes 필드의 Reverse accessor과 owner 필드의 Reverse accessor가 충돌이 난단다! 흠냐.

 

찬찬히 생각해보면 문제가 생기는 게 당연해 보인다!

BlogUser는 현재 Post 모델의 owner과 ForeignKey관계로 참조된 상태.

우리가 멋대로 likes란 녀석을 BlogUser과 다대다 관계로 참조를 시키는 순간...

BlogUser에서 Post 모델을 역참조 할 때 owner과 likes 중 어느 필드를 가져와야 하는지 알지 못한다!! 컴퓨터 바보.

 

그럼 어떻게 해야하는겨! owner과 likes가 각각 Post의 다른 속성임을 알려주면 된다.

이를 가능하게 하는 것이? related_name.

related_name을 통해 BlogUser가 Post를 역참조 할 때 likes란 이름을 참조할 수 있도록 명시해주면 된다.

 

admin

쨔잔. 그럼 이렇게 Post 안에 Likes를 누른 BlogUser를 표시할 수 있게 된다.

위에 있는 owner와 비교하면 ForeignKey와 ManyToManyField와의 차이가 확연해진다!

이들 중 Likes를 가지고 있는 BlogUser의 숫자가 바로 해당 게시글의 좋아요 횟수가 될 것이다.

 

2. urls 작성

urls.py

좋아요를 위해서는? 

1. 어떤 게시글인지. 2. 누가 눌렀는지.

이 두 가지 정보가 필요할 것이다!

그런데 user는? Form을 제출하는 순간 request를 통해 그 정보가 넘어간다.

따라서 해당 게시글이 무엇인지를 판단하기 위해 post_id와 slug를 넘겨준다!

 

3. view 작성

본격적으로 view를 작성하기 전에... 어떤 흐름으로 구현하면 좋을지 생각해보자.

 

1) Form을 통해 POST 요청을 보낸다. 

이때, 좋아요는 로그인 한 유저가 요청했을 경우에만 유효한 것으로 취급하도록!

2) 요청이 들어온, 즉 좋아요를 누른 게시글을 불러온다.

3) 해당 게시글의 Likes 필드에 해당 유저가 있을 경우 삭제, 없을 경우 추가한다.

 

말은 엄청 쉽다! 우와!

 

views.py

차근차근 살펴보자...

 

1) Form을 통해 POST 요청을 보낸다.

이때, 좋아요는 로그인 한 유저가 요청했을 경우에만 유효한 것으로 취급하도록!

우선 요청한 유저, 즉 request.user를 user로 지정해준다.

if문을 사용해 POST 요청일 경우, 그리고 user가 로그인되어있을 경우 함수가 작동하도록!

 

user가 로그인 되어있을 경우? → is_authenticated 를 사용한다! 로그인되어있으면 True를 반환하는 메서드.

반대로 로그인되어있지 않을 경우를 찾고 싶다면? → 반대 격인 is_anonymous 를 사용하면 된다!

 

2) 요청이 들어온, 즉 좋아요를 누른 게시글을 불러온다.

우선 게시글을 불러오기 위해 objects.get을 사용!

Post 모델의 수많은 게시글 중 어느 것을? → pk가 요청이 들어온 post_id인 것을!

 

3) 해당 게시글의 Likes 필드에 해당 유저가 있을 경우 삭제, 없을 경우 추가한다.

요청받은 게시글을 mylike라고 지정했다.

이 게시글의 필드 속성 중 하나인 likes에 요청한 유저가 있는지 없는지만 판단하면 해결!

이를 위해 filter함수를 사용한다. filter → 해당 조건에 맞는 객체를 반환하도록!

 

여기서는 요청을 보낸 유저가 있는지 없는지를 가려내야 하므로, 조건을 user.id가 있는지 없는지로.

이를 위해 .exists()함수를 썼다.(s를 빼먹지 않도록 주의하자)

 

있을 경우, likes필드에서 해당 user를 제거!

없을 경우, likes필드에 해당 user를 추가!

 

user가 로그인되어있지 않은 상태로 요청을 보낼 경우, 로그인을 위해 해당 함수로 redirect 시켜줬다.

 

3. templates 작성

좋아요는 해당 글의 detail 페이지에 이뤄질 테다.

detail.html

좋아요 함수를 작동시키는 건 뭐... 흔한 form 작성이다.

 

중요한 건 그 밑! 

앞서 좋아요의 정체는 그냥 0에서 하나하나 올라가는 게 아니라... likes필드에 있는 user 숫자의 합이라고 했다!

 

이를 세기 위해? likes.count를 이용하면 likes필드에 있는 객체의 숫자를 세준다. 편리하구만!

 

blogs/post/Slug/

구현된 모습. lee로 로그인해서 좋아요를 누르면 숫자가 올라가고, 다시 좋아요를 누르면 숫자가 내려간다. 성공!

728x90
반응형