1 개요편집
어떤 게시물을 추천하거나 북마크, 즐겨찾기 저장하는 등의 기능을 구현해보고자 한다. 셋 다 유사한 성격을 띄고 있어 같은 로직으로 짤 수 있다. 이름만 바꿔주면 작동한다.
게시글을 추천하거나 나중에 보기 위해 즐겨찾기하는 기능이 필요하다.
2 모델 수정편집
기존 글의 모델에 다음과 같이 필요한 속성을 추가한다.
voter = models.ManyToManyField(settings.AUTH_USER_MODEL)
like_count = models.IntegerField(default=0) # 불필요한 연산 없이 진행하기 위해.
그런데, 이렇게 수정하고 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함수를 사용하여 추천인을 추가해야 한다.
4.1 참조테이블을 자동으로 생성한 경우편집
@login_required()
def posting_like(request, posting_id):
posting = get_object_or_404(Posting, pk=posting_id)
if posting.like_users.filter(id=request.user.id).exists():
posting.like_users.remove(request.user) # 이미 추가되어 있다면 삭제한다.
posting.like_count -= 1
posting.save() # save가 있어야 반영된다.
else:
posting.like_users.add(request.user) # 포스팅의 likeUser에 user를 더한다.
posting.like_count += 1
posting.save()
return redirect('scientific_humor:detail', posting_id=posting_id)
4.2 중간 참조테이블을 직접 정의한 경우편집
@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>
이 경우에 모델에서 정의했던 like_count는 지워도 된다. like_count를 이용하는 경우 바로 question.like_count를 넣으면 된다.
5.3 추천 여부에 따라 버튼 다르게 나타내기편집
{% if user in post.like_user_set.all %} <!--추천 모델 안에 유저가 있다면..--!>
<div class = 'like-btn active' .....
{% else %}
<div class = 'like-btn' .....
{% endif %}
6 마침편집
위 작업은 추천 데이터의 반영을 창을 새로 고침으로써 수행했다. 실시간, 비동기 반영을 원하면 장고 실시간 추천 문서를 참고하도록 하자.