django 좋아요 ajax와 @property

2019-05-03
#models.py
class Post(models.Model, HitCountMixin):
    ...
    like_user_set = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                        blank=True,
                                        related_name='like_user_set',
                                        through='Like')
    
    @property # ajax 쓸 때 like_count의 변수를 읽고, 변경하기 위해 꼭 적어야 한다.
    def like_count(self):
        return self.like_user_set.count() # related_name을 'like_user_set'으로 설정했기에
    					  # 쉽게 like_user_set.count()로 가져다 사용가능
        
class Like(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

@property는 변수를 변경할 때 특정한 제한을 두고 싶을 때 사용하기도 하지만 getter setter 없이도 쉽게 값을 읽고 변경하고 싶을 때도 사용하는 것 같다. 실제로 이후에 만들 post_like 함수를 만들고 Ajax 통신을 할 때 @property가 선언이 되어있지 않다면 TypeError: Object of type 'method' is not JSON serializable 이런 오류나 json dumps 관련 에러가 발생한다. 일부러 복사 붙여넣기 안 한다고 보면서 이해하면서 코드를 치다 보니 @property 하나를 빼먹어서 결국 2시간을 소모했다. 함수를 반환 못한다는 게 설마 저 값을 함수에서 못 가져온다는 의미인 줄은 몰랐다…

#urls.py
path('like/', views.post_like, name='post_like'),
#views.py
@login_required
@require_POST
def post_like(request):
    pk = request.POST.get('pk', None) # ajax를 통해 POST 방식으로 template에서 작동
    post = get_object_or_404(Post, pk=pk)
    post_like, post_like_created = post.like_set.get_or_create(user=request.user)

    if not post_like_created:
        post_like.delete()
    else:
        pass

    context = {'like_count': post.like_count}
    return HttpResponse(json.dumps(context), content_type="application/json")
    # json 타입으로 반환

views.py의 post_like의 코드는 개인에 맞게 고쳐 사용하면 된다.

좋아요를 누를 때마다 message를 뿌려주는 건 사용자 경험에 좋지 않다고 생각해서 없앴고

nickname은 아직 제대로 이해를 못 해서 넣지 않았다.

이해도 못 하면서 전부 다 할 수는 없으니까…

<!--post_detail.html-->
<button class="btn btn-outline-info"><i class="like fas fa-heart" name="{{post.pk}}">
	<p id="count-{{post.pk}}">{{ post.like_count }}개</p></i></button>
	<!--좋아요 버튼-->

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
	<script type="text/javascript">
		$(".like").click(function(){ // 버튼을 click하면 class의 like를 가져와서 ajax 기능 시작
			var pk = $(this).attr('name')
			$.ajax({
				type: "POST", // 데이터 전송 타입
				url: "{% url 'posts:post_like'%}", // 새로고침은 안하지만 데이터를 보낼 url은 필요하므로 보낼 url 지정
				data: {'pk': pk, 'csrfmiddlewaretoken': '{{csrf_token}}'},
				dataType: "json",
				// post_like에서 반환하기로 한 데이터 타입 json {'like_count': post.like_count}을 반환
            
				success: function(response){ // 통신 성공시 수행
					$("#count-"+pk).html(response.like_count+"");
				},
				error: function(request, status, error){ // 통신 실패시 수행
					alert("로그인이 필요합니다.")
					window.location.replace("/accounts/login/")
				},
			})
		})
	</script>

이렇게하면 ajax를 이용한 좋아요 구현은 끝!

아직 코드를 완벽하게 이해를 하진 못했지만 ajax를 다른 곳에도 더 적용 시키면서 연습을 하면 어떻게든 되지 않을까(?)

코드전체