django 좋아요 ajax와 @property
- 참조
#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를 다른 곳에도 더 적용 시키면서 연습을 하면 어떻게든 되지 않을까(?)