수학과의 좌충우돌 프로그래밍

[Django] 좋아요 기능 구현하기 (ajax 사용 x) 본문

웹프로그래밍/Django

[Django] 좋아요 기능 구현하기 (ajax 사용 x)

ssung.k 2019. 7. 23. 18:28

SNS 를 비롯해서 많은 사이트에는 좋아요, 하트 라고 불리는 기능이 있습니다. 아마 다들 뭔지 아실거라고 생각합니다. 이번에는 이 기능을 구현해보도록 하겠습니다.

그러기 위해서 부가적으로 구현되어야 할 것이 많습니다. 유저부터 시작해서 게시물 등 많지만 이 부분은 앞선 포스팅에도 있으므로 빠르게 넘어가도록 하겠습니다. 추가적으로 기능 구현에 주를 두고 있으므로 templates 의 디자인적인 부분은 아예 신경 쓰지 않았습니다.

 

좋아요 기능 구현

위에서 말했듯이 이번에 알아볼 중요 코드 외에 부가적인 코드가 많습니다. 그 부분 보다는 좋아요를 위한 코드 위주로 설명을 하도록 하겠습니다.

# like/models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    nickname = models.TextField(max_length=10)

    like_posts = models.ManyToManyField('Post', blank=True, related_name='like_users')

    def __str__(self):
        return self.nickname

class Post(models.Model):
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
    title = models.CharField(max_length=30)
    content = models.TextField()
    pub_date = models.DateTimeField(auto_now_add=True)

    like_count = models.PositiveIntegerField(default=0)

    def __str__(self):
        return self.title

Profile 은 django의 User 를 OtO 으로 연결 시켜 확장한 모델이고 Post 는 게시물에 해당하는 모델입니다. 이 두 모델을 연결하여 좋아요를 구현할 수 있습니다. 유저 입장에서도 여러 게시물에 좋아요를 누를 수 있고 게시물 입장에서도 여러 유저한테 좋아요를 받을 수 있기 떄문에 MtM 로 연결이 되어야 할 것 입니다. Profile 의 필드에서 이를 찾을 수 있습니다.

like_posts = models.ManyToManyField('Post', blank=True, related_name='like_users')

PostProfile 보다 아래 있기 때문에 문자열로서 관계를 지어주었습니다. 또한 유저가 처음 생길 때는 어떤 게시물 하고도 관계가 없기 때문에 blank=True, 그리고 related_name 으로 반대쪽 모델에 접근 하기 위한 이름을 따로 지어주었습니다.

게시물의 좋아요 수는 Post 내에서 필드를 새롭게 만들어 주었습니다.

    like_count = models.PositiveIntegerField(default=0)

처음에는 좋아요 수가 0개 이므로 default=0 을 설정해두었습니다.

 

<!-- templates/like/post_detail.html -->

<a href="{% url 'like:main' %}">뒤로 가기</a>

<div>제목</div>
<div>{{post.title}}</div>
<div>날짜</div>
<div>{{post.pub_date}}</div>
<div>내용</div>
<div>{{post.content}}</div>

<div>좋아요 수 : {{post.like_count}}</div>

<a href="{% url 'like:post_like_toggle' post.id %}">
    {% if post in user.profile.like_posts.all %}
        취소
    {% else %}
        좋아요
    {% endif %}
</a>

가장 아래 a링크 있는 부분을 보도록 합시다. 해당 유저가 좋아요한 Post 를 모두 가지고 와서 현재 post 가 그 안에 있는 지 확인 합니다. 만약 있다고 하면 좋아요를 이미 누른 것이니 취소를 보여주고, 그렇지 않으면 좋아요 를 보여주도록 합시다.

 

필요없는 부분은 전부 생략하고 좋아요 를 눌렀을 때 넘어갈 url 만 남겨주었습니다.

# config/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('like/', include('like.urls')),
]

 

# like/urls.py

from django.urls import path
from . import views

app_name = 'like'

urlpatterns = [
    # 생략
    path('post_like_toggle/<int:post_id>/', views.post_like_toggle, name="post_like_toggle"),
]

 

마찬가지로 좋아요 를 눌렀을 때 실행되는 함수만 남겨주었습니다.

# like/views.py

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.contrib import auth
from .models import Profile, Post
from django.contrib.auth.decorators import login_required

@login_required
def post_like_toggle(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    user = request.user
    profile = Profile.objects.get(user=user)

    check_like_post = profile.like_posts.filter(id=post_id)

    if check_like_post.exists():
        profile.like_posts.remove(post)
        post.like_count -= 1
        post.save()
    else:
        profile.like_posts.add(post)
        post.like_count += 1
        post.save()

    return redirect('like:post_detail', post_id)

가장 위에 @login_required 를 통해서 login 을 했을 시에만 해당 함수에 접근이 가능하도록 했습니다. 우선 현재 로그인하고 있는 유저와 해당 게시물에 해당되는 profilepost 를 가져옵니다. 다음으로는 유저가 해당 게시물을 좋아요를 했는지 안했는지를 check_like_post 통해 확인해줍니다. 좋아요를 눌렀다면 check_like_post 가 존재할 것이고 좋아요를 누르지 않았다면 비어 있을 것 입니다. 이를 통해서 좋아요의 값을 증가 혹은 감소 시키고 저장시켜줍니다.

 

지금까지 간단하게 좋아요 기능에 대해서 알아보았습니다. 하지만 보통 좋아요 기능을 보면 버튼을 눌러도 화면이 redirect 되지 않습니다. 이를 위해 다음에는 ajax 를 통해서 좋아요 기능을 구현해보도록 하겠습니다.

Comments