▶️ Django 

[▶️Back-end] 메인 페이지에 좋아요, 싫어요 버튼 기능 구현 1차

 

Like 모델을 추가했어요.

그와 관련된 views.py, urls.py도 추가했어요.


Like 모델 구현 시작!

⚙️ articles/models.py

더보기
더보기
# articles/models.py

# Like 모델
class Like(models.Model):
    """
    유저가 게시글에 좋아요/싫어요 누른 정보를 저장하는 모델이에요.
    """
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="user_likes"
    )
    article = models.ForeignKey(
        Article, on_delete=models.CASCADE, related_name="article_likes"
    )
    like_type = models.CharField(
        max_length=10, choices=(("Like", "like"), ("Dislike", "dislike"))
    )
    
    # 유저-게시글 조합은 유일해야 함. 중복 좋아요 방지
    class Meta :
        unique_together = ("user", "article")
        
    def __str__(self):
        return f"{self.user.username} - {self.article.title} - {self.like_type}"

⚙️ articles/urls.py

더보기
더보기
from django.urls import path
from django.conf.urls.static import static
from django.conf import settings
from .views import ArticleList, ArticleLike

app_name = "articles"
urlpatterns = [
    path("", ArticleList.as_view(), name="main"), # 게시물 목록
    # article_id와 like_type을 URL 피라미터로 받음 ⬇️
    path("articles/<int:id>/like/<str:like_type>/", ArticleLike.as_view(), name="articlelike"),
]

⚙️ articles/views.py

더보기
더보기
from django.shortcuts import render, get_object_or_404 , redirect
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin # 로그인한 사용자만 특정 view에 접근할 수 있음
from .models import Article, Like
from django.http import HttpResponseForbidden # error 403(서버에 요청은 갔지만, 권한 때문에 요청 거절)

...

# 좋아요 게시물
class ArticleLike(LoginRequiredMixin, View): # 로그인 필수 기능 추가
    login_url = "/users/login/" # 로그인 되지 않았으면 로그인 url로 보냄
    
    def post(self, request,id, like_type): # 이렇게 적으면 article_id를 URL에서 받음
        article = get_object_or_404(Article, pk=id)
        user = request.user # 현재 로그인한 유저
        
        # like_type 유효성 검사 (모델 choices 사용)
        valid_like_types = [choice[0] for choice in Like.like_type.field.choices] #Like 모델 필드 LikeType의 choices 속성 사용
        if like_type not in valid_like_types:
            return HttpResponseForbidden("잘못된 요청입니다.")

        # 이미 좋아요/싫어요를 누른 경우 (예 : 취소 또는 변경)
        try:
            existing_like = Like.objects.get(user=user, article=article)
            if existing_like.like_type == like_type:
                # 같은 종류의 좋아요/싫어요를 다시 누른 경우 (예: 취소)
                existing_like.delete()
                
                if like_type == "like":
                    article.like_count = max(0, article.like_count - 1) # 최댓값 == 0, 게시물의 좋아요 개수에서 -1
                else:
                    article.dislike_count = max(0, article.dislike_count - 1) # 최댓값 == 0, like가 아니라 dislike일 경우
            else: # 예) 좋아요 -> 싫어요, 싫어요 -> 좋아요
                # 다른 종류의 좋아요/싫어요로 변경
                if like_type == "like":
                    article.like_count += 1
                    article.dislike_count = max(0, article.dislike_count - 1) # 싫어요 -> 좋아요로 간 경우임
                else:
                    article.like_count = max(0, article.like_count - 1)
                    article.dislike_count += 1
                existing_like.like_type = like_type
                existing_like.save() # 좋아요 또는 싫어요 관련 정보 저장.
            
            article.save() # 해당 게시물 저장
            
        except Like.DoesNotExist:
            # 좋아요/싫어요를 처음 누른 경우
            Like.objects.create(user=user, article=article, like_type=like_type)
            if like_type == "like":
                article.like_count += 1
            else:
                article.dislike_count += 1
            article.save()
        return redirect("articles:main") # 상세 페이지로 리다이렉션

오류 수정

코드 구현을 끝낸 후 장고 서버에 들어가 봤는데 오류가 터졌어요,, 네,,

⚙️ articles/models.py

더보기
더보기
# articles/models.py

# Like 모델
class Like(models.Model):
    """
    유저가 게시글에 좋아요/싫어요 누른 정보를 저장하는 모델이에요.
    """
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="user_likes"
    )
    article = models.ForeignKey(
        Article, on_delete=models.CASCADE, related_name="article_likes"
    )
    like_type = models.CharField(
        max_length=10, choices=(("❤️", "like"), ("🤨", "dislike"))
    )
    
    # 유저-게시글 조합은 유일해야 함. 중복 좋아요 방지
    class Meta :
        unique_together = ("user", "article")
        
    def __str__(self):
        return f"{self.user.username} - {self.article.title} - {self.like_type}"

 

<수정한 내용>

like_type = models.CharField(
        max_length=10, choices=(("❤️", "like"), ("🤨", "dislike"))
    )

 

choices 부분을 수정했어요.

 

choices는

  • 튜플로 구성돼 있어요.
  • (A, B)
    • A : DB에 저장될 값
    • B : 사람이 읽을 수 있는 라벨

이렇게 구성돼 있어요.

 

❤️를 누르면 like가 되는 것이고, 🤨를 누르면 dislike가 돼요.

⚙️ articles/views.py

<수정 내용>

if like_type == "like":

 

이 부분을

if like_type == "❤":

이렇게 바꾸어주었어요.

왜냐면 models.py에 choices를 ❤️와 🤨로 바꾸었기 때문이에요!

 

<전체 views.py>

더보기
더보기
from django.shortcuts import render, get_object_or_404 , redirect
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin # 로그인한 사용자만 특정 view에 접근할 수 있음
from .models import Article, Like
from django.http import HttpResponseForbidden # error 403(서버에 요청은 갔지만, 권한 때문에 요청 거절)


# 좋아요 게시물
class ArticleLike(LoginRequiredMixin, View): # 로그인 필수 기능 추가
    login_url = "/users/login/" # 로그인 되지 않았으면 로그인 url로 보냄
    
    def post(self, request,id, like_type): # 이렇게 적으면 article_id를 URL에서 받음
        article = get_object_or_404(Article, pk=id)
        user = request.user # 현재 로그인한 유저
        
        # like_type 유효성 검사 (모델 choices 사용)
        valid_like_types = [choice[0] for choice in Like.like_type.field.choices] #Like 모델 필드 LikeType의 choices 속성 사용
        if like_type not in valid_like_types:
            return HttpResponseForbidden("잘못된 요청입니다.")

        # 이미 좋아요/싫어요를 누른 경우 (예 : 취소 또는 변경)
        try:
            existing_like = Like.objects.get(user=user, article=article)
            if existing_like.like_type == like_type:
                # 같은 종류의 좋아요/싫어요를 다시 누른 경우 (예: 취소)
                existing_like.delete()
                
                if like_type == "❤️":
                    article.like_count = max(0, article.like_count - 1) # 최댓값 == 0, 게시물의 좋아요 개수에서 -1
                else:
                    article.dislike_count = max(0, article.dislike_count - 1) # 최댓값 == 0, like가 아니라 dislike일 경우
            else: # 예) 좋아요 -> 싫어요, 싫어요 -> 좋아요
                # 다른 종류의 좋아요/싫어요로 변경
                if like_type == "❤️":
                    article.like_count += 1
                    article.dislike_count = max(0, article.dislike_count - 1) # 싫어요 -> 좋아요로 간 경우임
                else:
                    article.like_count = max(0, article.like_count - 1)
                    article.dislike_count += 1
                existing_like.like_type = like_type
                existing_like.save() # 좋아요 또는 싫어요 관련 정보 저장.
            
            article.save() # 해당 게시물 저장
            
            
        except Like.DoesNotExist:
            # 좋아요/싫어요를 처음 누른 경우
            Like.objects.create(user=user, article=article, like_type=like_type)
            if like_type == "❤️":
                article.like_count += 1
            else:
                article.dislike_count += 1
            article.save()
        return redirect("articles:main") # 상세 페이지로 리다이렉션

 

+ Recent posts