장고 추천기능

Sam (토론 | 기여)님의 2021년 6월 25일 (금) 10:28 판

1 개요

어떤 게시물을 추천하거나 북마크, 즐겨찾기 저장하는 등의 기능을 구현해보고자 한다. 셋 다 유사한 성격을 띄고 있어 같은 로직으로 짤 수 있다. 이름만 바꿔주면 작동한다.

게시글을 추천하거나 나중에 보기 위해 즐겨찾기하는 기능이 필요하다.

2 모델 수정

기존 글의 모델에 다음과 같이 필요한 속성을 추가한다.

voter = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True,null=True)

그런데, 이렇게 수정하고 DB에 반영하면 에러가 뜬다. 게시글의 작성자와 voter에 들어가는 사람이 둘 다 User모델을 참조하기 있기 때문에 User모델로 하위모델에 접근하려고 할 때 작성자를 기준으로 찾아야 할지, 추천자를 기준으로 찾아야 할지 정해지지 않기 때문이다.

=> 두 모델에 related_name 이라는 속성을 주어 User.옵션명.all 형태로 접근할 수 있다.

2.1 혹은 이런 모델..

위처럼 해당 객체 아래에 다대다 관계를 만들어 연동할 수도 있지만, 다음과 같이 모델 자체를 따로 만드는 방법도 있다.

복잡한 모델을 구현할 땐 다음과 같이 중간모델을 만들기도 한다. 바로 ManyToMany로 잇기보단, 다음과 같이 중간모델을 만드는 게 일반적이다.

class Post(models.Model):
    ...
    like_user = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Like')  # through는 연결할 모델을 의미한다.

class Like(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    writing = models.ForeignKey(모델명, on_delete=models.CASCADE)
    create_at = models.DateTimeField(auto_add_now=True)
    
    class Meta:
        unique_together = (
            ('user','post')
            )

모델을 위와 같이 짜면 좋아요를 날짜에 맞게 정렬할 수 있고, 기능을 추가하거나 수정하기 용이해진다. 때문에 굳이 위와 같이 새로운 모델을 만들어 사용한다.

3 url 추가

path('comment/vote/<int:question_id>/', views.vote, name='vote'),

4 뷰 추가

ManyToMany 필드는 add함수를 사용하여 추천인을 추가해야 한다.

@login_required(login_url='membership:login')
def vote_question(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    question_like, question_like_created = question.like_user.get_or_create(user=request.user)
    #위 함수가 어떤 기능인지 제대로 파악해야겠다.
    #question.voter.add(request.user)
    if not question_like_created:  # 생성된 게 아닌 경우.
        question_like.delete()  # 삭제한다.
    return redirect('pool:detail', question_id=comment.answer.question.id)

동일한 글을 여러번 추천하더라도 추천수가 증가하진 않는다. 중복은 허락되지 않기 때문.

5 탬플릿 수정

5.1 추천버튼

<a href="{% url 'pool:vote' question.id%}" class="btn btn-primary">추천</a>

5.2 추천갯수 나타내기

적당한 곳에 다음과 같은 코드를 담는다.

<div class="text-center">추천한 사람 수:{{question.voter.count}}</div>

6 마침

위 작업은 추천 데이터의 반영을 창을 새로고침으로써 수행했다. 실시간, 비동기 반영을 원하면 장고 실시간 추천 문서를 참고하도록 하자.