[Python] django 게시판 추천, 좋아요 기능 구현하기
게시판에 있는 추천(좋아요) 기능을 구현하는 방법입니다.
- 모델변경
- ) Question 모델 변경
- ) Answer 모델 변경
- ) mikemigration, migrate 명령어 실행
- 질문 추천
- ) 질문 추천 버튼
- ) 추천 버튼 확인 창
- ) 질문 추천 urls.py
- ) 질문 추천 views.py
- 답변 추천
- ) 답변 추천 버튼
- ) 답변 추천 urls.py
- ) 답변 추천 views.py
1. 모델 변경
먼저 추천(좋아요) 기능은 하나의 질문에 여러명이 추천할 수 있고 한 명이 여러 개의 질문에 추천할 수 있으므로 "다대다(N:N)" 관계를 의미하는 ManyToManyField를 사용해야 합니다.
추천(좋아요)를 나타내는 User모델의 voter 속성을 Question 모델과 Answer 모델에 정의해줘야 합니다.
그러나 기존 author 속성도 User 모델을 사용하므로 새롭게 추가하는 voter 속성과 충돌이 날 수 있습니다.
이 이유는 장고에서 User 모델을 통해서 Question 데이터에 접근하려고 할 때 author를 기준으로 할지 voter를 기준으로 해야 할지 명확하지 않아 오류가 발생합니다.
이럴 땐 related_name 인수를 추가하여 author 속성과 voter 속성을 구별해줘야 합니다.
1-1) Question 모델 변경
mysite\pybo\models.py 파일의 Question 모델을 다음과 같이 수정합니다.
class Question(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_question') #수정
subject = models.CharField(max_length=200)
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(User, related_name='voter_question') #추가
위와 같이 author 속성에 related_name='author_question' 인수를 선언합니다.
voter는 ManyToManyField 를 사용하여 related_name='voter_question' 인수를 선언합니다.
이제 author 속성에 접근할 때는 author_question.all()와 같이 사용하고 voter 속성에 접근하고자 할때는 voter_question.all() 과 같이 접근합니다.
1-2) Answer 모델 변경
마찬가지 방법으로 Answer 모델도 추천인(voter) 속성을 다음과 같이 정의합니다.
class Answer(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_answer')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(User, related_name='voter_answer')
1-3) makemigration 명령어와 migrate 명령어 실행
모델이 변경되었으니 (데이터베이스 변경) makemigration, migrate 명령어를 차례대로 수행합니다.
(myvenv) c:\projects\mysite>python manage.py makemigrations
Migrations for 'pybo':
pybo\migrations\0005_auto_20221206_1747.py
- Add field voter to answer
- Add field voter to question
- Alter field author on answer
- Alter field question on answer
- Alter field author on question
(myvenv) c:\projects\mysite>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, pybo, sessions
Running migrations:
Applying pybo.0005_auto_20221206_1747... OK
(myvenv) c:\projects\mysite>
2.질문 추천
2-1) 질문 추천 버튼
추천(좋아요) 버튼을 질문 상세 페이지에 작성합니다.
mysite\templates\pybo\question_detail.html 파일에 수정 버튼과 삭제 버튼 정의한 구문 위에 추천 버튼을 다음과 같이 작성합니다.
<div class="my-3">
<!-- 추천 버튼 추가 시작 -->
<a href="javascript:void(0)" data-uri="{% url 'pybo:question_vote' question.id %}"
class="recommend btn btn-sm btn-outline-secondary"> 추천
<span class="badge rounded-pill bg-success">{{question.voter.count}}</span>
</a>
<!-- 추천 버튼 추가 끝 -->
{% if request.user == question.author %}
<a href="{% url 'pybo:question_modify' question.id %}"
class="btn btn-sm btn-outline-secondary">수정</a>
<a href="javascript:void(0)" class="delete btn btn-sm btn-outline-secondary"
data-uri="{% url 'pybo:question_delete' question.id %}">삭제</a>
{% endif %}
</div>
추천 버튼과 함께 question.voter.count 로 추천수도 함께 보이도록 설정했습니다.
그리고 버튼을 클릭하면 href 속성이 javascript.void(0) 으로 설정되어 있기 때문에 아무런 동작도 하지 않고 class 속성에 "recommned"를 추가하여 자바스크립트로 data-uri에 정의된 URL이 호출됩니다. 이는 "추천" 버튼에 대한 확인창을 팝업시키기 위함입니다.
2-2) 추천 버튼 확인 창
추천 버튼을 클릭했을 때 "정말로 추천 하시겠습니까?" 라는 기능 구현을 위해 질문 상세 페이지에 다음과 같이 작성합니다.
mysite\templates\pybo\question_detail.html
{% block script %}
<script type='text/javascript'>
const delete_elements = document.getElementsByClassName("delete");
Array.from(delete_elements).forEach(function(element) {
element.addEventListener('click', function() {
if(confirm("정말로 삭제하시겠습니까?")) {
location.href = this.dataset.uri;
};
});
});
<!-- 아래 추가 시작 -->
const recommend_elements = document.getElementsByClassName("recommend");
Array.from(recommend_elements).forEach(function(element) {
element.addEventListener('click', function() {
if(confirm("정말로 추천 하시겠습니까?")) {
location.href = this.dataset.uri;
};
});
<!-- 아래 추가 끝 -->
});
</script>
{% endblock %}
2-3) 질문 추천 urls.py
<a href="javascript:void(0)" data-uri="{% url 'pybo:question_vote' question.id %}"
구문의 URL에 추가되었으므로 pybo/urls.py 에 URL 매핑 규칙을 정의합니다.
mystite\pybo\urls.py 파일을 다음과 구문을 추가합니다.
path('question/vote/<int:question_id>/', question_views.question_vote, name='question_vote'),
2-3) 질문 추천 views.py
URL 매핑에 의해 실행되는 question_vote 함수를 다음과 같이 정의합니다.
mysite\pybo\views\question_views.py
@login_required(login_url='common:login')
def question_vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
if request.user == question.author:
messages.error(request, '본인이 작성한 글은 추천할수 없습니다')
else:
question.voter.add(request.user)
return redirect('pybo:detail', question_id=question.id)
로그인한 사용자와 글쓴이가 같다면 추천할 수 없도록 설정했습니다. 그리고 Question 모델의 voter는 여러 사람이 추천할 수 있으므로 add 함수를 사용하여 추천인을 추가했습니다.
else:
question.voter.add(request.user)
3. 답변 추천
3-1) 답변 추천 버튼
질문 추천이랑 동일합니다. 질문 상세 페이지에 추천 버튼을 다음과 같이 추가합니다.
<div class="my-3">
<!-- 추천 버튼 아래 추가 -->
<a href="javascript:void(0)" data-uri="{% url 'pybo:answer_vote' answer.id %}"
class="recommend btn btn-sm btn-outline-secondary"> 추천
<span class="badge rounded-pill bg-success">{{answer.voter.count}}</span>
</a>
<!-- 추천 버튼 아래 추가 끝 -->
{% if request.user == answer.author %}
<a href="{% url 'pybo:answer_modify' answer.id %}"
class="btn btn-sm btn-outline-secondary">수정</a>
<a href ="#" class="delete btn btn-sm btn-outline-secondary"
data-uri="{% url 'pybo:answer_delete' answer.id %}">삭제</a>
{% endif %}
</div>
3-2) 답변 추천 urls.py
mysite\pybo\urls.py 파일에 다음과 같이 URL 매핑 규칙을 추가합니다.
path('answer/vote/<int:answer_id>/', answer_views.answer_vote, name='answer_vote'),
3-3) 답변 추천 views.py
위에서 정의한 URL 매핑에 의해 실행되는 answer_vote 함수를 다음과 같이 정의합니다.
mysite\pybo\views\answer_views.py
@login_required(login_url='common:login')
def answer_vote(request, answer_id):
answer = get_object_or_404(Answer, pk=answer_id)
if request.user == answer.author:
messages.error(request, '본인이 작성한 글은 추천할수 없습니다')
else:
answer.voter.add(request.user)
return redirect('pybo:detail', question_id=answer.question.id)
'IT > Linux' 카테고리의 다른 글
[Python] django 마크다운 설치 (0) | 2022.12.08 |
---|---|
[Python] django 앵커(anchor) 기능 구현하기 (0) | 2022.12.08 |
[Python] django 뷰 파일 분리 (0) | 2022.12.05 |
[Python] django 게시판 작성된 글 수정 및 삭제 기능 구현 (0) | 2022.12.01 |
[Python] django 게시판 글쓴이 표시 (2) (2) | 2022.11.25 |
댓글