여름의 서재

[Django] 좋아요 기능 구현하기_Like 본문

Skill/Django

[Django] 좋아요 기능 구현하기_Like

엉아_ 2021. 10. 24. 15:37
728x90

💡 Article과 Like는 무슨 관계일까?

: 한 게시글은 여러명에게 좋아요를 받을 수 있다. 또한 한 사람은 여러개의 게시글에 좋아요를 할 수 있다.

즉, Article과 Like_user는 N:N 관계를 가진다.

 

🔧 좋아요 기능 구현하기

1. articles/models.py

: ''유저는 게시글을 좋아한다.'' 여기서 table은 유저 테이블과 게시글 테이블이 사용되고 중간에 좋아요라는 행위가 중개테이블이 된다. 그래서 Article model에 user 테이블과 연결하는 like_users라는 이름의 manytomany 필드를 만들어야 한다.

 

이때, 꼭! related_name을 설정해줘야 한다. 그렇지 않으면 게시글을 작성한 유저를 나타내는 user 필드의 매니저와 충돌하게 된다. 둘다 user 테이블과 연결된 필드이기 때문에 manager가 user_set으로 표현된다. 그렇기 때문에 related_name을 써서 manager 충돌을 막아주자.

 

# articles/models.py

from django.db import models
from django.conf import settings

# Create your models here.
class Article(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    like_users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='like_articles')
    title = models.CharField(max_length=10)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

 

2. migrations & migrate

: DB 테이블을 변경해줬으니 migrate는 필수!!

python manage.py migrations
python manage.py migrate

 

3. articles/urls.py

: 좋아요를 추가하고 삭제할 때 쓰이는 url을 만들어준다.

from django.urls import path
from . import views


app_name = 'articles'
urlpatterns = [
    # 생략
    path('<int:article_pk>/likes/', views.likes, name='likes'),
]

 

 

4. articles.views.py

: 로그인이 된 유저일때만 좋아요 기능을 이용할 수 있다. 만약 요청이 들어왔을 때 현재 유저가 해당 게시글을 좋아요한 사람 중 한명이라면 좋아요를 취소하고, 아직 좋아요를 하지 않았다면 좋아요 한 사람에 현재 유저를 추가한다.

 

📌 article.like_users.filter(pk=request.user.pk).exists()

: 해당 게시글을 좋아요한 사람중에 pk가 현재 유저의 pk랑 같은 것이 존재하는지 하지 않는지를 판단한다.

request.user.like_articles.(pk=article_pk).exist() 라고 써도 같은 뜻이 된다.

 

@require_POST
def likes(request, article_pk):
    if request.user.is_authenticated:
        article = get_object_or_404(Article, pk=article_pk)

        if article.like_users.filter(pk=request.user.pk).exists():
            article.like_users.remove(request.user)
        else:
            article.like_users.add(request.user)
        return redirect('articles:index')
    return redirect('accouts:login')

 

5. templates

: 원하는 템플릿에 좋아요 버튼을 넣어준다. 현재 유저가 좋아요를 이미 한 상태라면 '좋아요 취소' 글씨를 출력하고, 아니라면 '좋아요' 글씨를 출력한다.

    <div>
      <form action="{% url 'articles:likes' article.pk %}" method='POST'>
        {% csrf_token %}
        {% if user in article.like_users.all %}
          <input type="submit" value='좋아요 취소'>
        {% else %}
          <input type="submit" value='좋아요'>
        {% endif %}
      </form>
    </div>

 

-> 글씨 대신 아이콘을 이용해서 빈 하트, 채워진 하트를 넣는 것도 가능하다!

  <form action="{% url 'community:like' review.pk %}" method='POST'>
    {% csrf_token %}
    {% if review in user.like_reviews.all %}
      <button class="btn btn-link text-danger">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-suit-heart-fill" viewBox="0 0 16 16">
          <path d="M4 1c2.21 0 4 1.755 4 3.92C8 2.755 9.79 1 12 1s4 1.755 4 3.92c0 3.263-3.234 4.414-7.608 9.608a.513.513 0 0 1-.784 0C3.234 9.334 0 8.183 0 4.92 0 2.755 1.79 1 4 1z"/>
        </svg>
      </button>
    {% else %}
      <button class="btn btn-link text-danger">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-suit-heart" viewBox="0 0 16 16">
          <path d="m8 6.236-.894-1.789c-.222-.443-.607-1.08-1.152-1.595C5.418 2.345 4.776 2 4 2 2.324 2 1 3.326 1 4.92c0 1.211.554 2.066 1.868 3.37.337.334.721.695 1.146 1.093C5.122 10.423 6.5 11.717 8 13.447c1.5-1.73 2.878-3.024 3.986-4.064.425-.398.81-.76 1.146-1.093C14.446 6.986 15 6.131 15 4.92 15 3.326 13.676 2 12 2c-.777 0-1.418.345-1.954.852-.545.515-.93 1.152-1.152 1.595L8 6.236zm.392 8.292a.513.513 0 0 1-.784 0c-1.601-1.902-3.05-3.262-4.243-4.381C1.3 8.208 0 6.989 0 4.92 0 2.755 1.79 1 4 1c1.6 0 2.719 1.05 3.404 2.008.26.365.458.716.596.992a7.55 7.55 0 0 1 .596-.992C9.281 2.049 10.4 1 12 1c2.21 0 4 1.755 4 3.92 0 2.069-1.3 3.288-3.365 5.227-1.193 1.12-2.642 2.48-4.243 4.38z"/>
        </svg>
      </button>
    {% endif %}
  </form>
Comments