질문이나 답변에 다른 사람들이 추천하는 기능을 추가하는 것을 시도한다. 이를 위해 Question, Answer 모델에 추천자를 의미하는 필드가 추가되어야 한다. 그리고 자신의 글에는 추천할 수 없도록 기능을 막는 것도 필요하다.
게시물 추천은 하나의 글에 여러 명이 추천하거나 한 명이 여러 게시물에 추천할 수 있다. 따라서 이 필드는 다대다 관계에 해당한다. Django에는 다대다 관계를 위한 ManyToManyField 함수를 지원한다.
Question 모델 수정
...
class Question(models.Model):
...
voter = models.ManyToManyField(User)
...
makemigration 실행
python manage.py makemigrations
SystemCheckError: System check identified some issues:
ERRORS:
pybo.Question.author: (fields.E304) Reverse accessor 'User.question_set' for 'pybo.Question.author' clashes with reverse accessor for 'pybo.Question.voter'.
HINT: Add or change a related_name argument to the definition for 'pybo.Question.author' or 'pybo.Question.voter'.
pybo.Question.voter: (fields.E304) Reverse accessor 'User.question_set' for 'pybo.Question.voter' clashes with reverse accessor for 'pybo.Question.author'.
HINT: Add or change a related_name argument to the definition for 'pybo.Question.voter' or 'pybo.Question.author'.
Question 모델에 related_model 추가
...
class Question(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_question')
...
voter = models.ManyToManyField(User, related_name='voter_question')
...
같은 방법으로 Answer 모델 수정
...
class Answer(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_answer')
...
voter = models.ManyToManyField(User, related_name='voter_answer')
...
makemigration, migrate 실행
python manage.py makemigrations
Migrations for 'pybo':
pybo/migrations/0006_answer_voter_question_voter_alter_answer_author_and_more.py
- Add field voter to answer
- Add field voter to question
- Alter field author on answer
- Alter field author on question
python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, pybo, sessions
Running migrations:
Applying pybo.0006_answer_voter_question_voter_alter_answer_author_and_more... OK
질문 상세 페이지 질문 추천 버튼 추가
<!--질문 내용 영역-->
<h2 class="border-bottom py-2">{{ question.subject }}</h2>
<div class="row my-3">
<!-- 추천 영역 Start-->
<div class="col-1">
<div class="bg-light text-center p-3 border font-weight-bolder mb-1">
{{ question.voter.count }}
</div>
<a href="#" data-uri="{% url 'pybo:vote_question' question.id %}" class="recommend btn btn-sm btn-secondary btn-block my-1">추천</a>
</div>
<!-- 추천 영역 End -->
<div class="col-11">
<div class="card">
<div class="card-body">
...
</div>
</div>
</div>
</div>
추천 확인 창 생성
지난 삭제 확인 창을 생성할 때와 같이 script 영역에 추천 확인 창을 생성하는 script를 작성
...
{% block script %}
<script type="text/javascript">
$(document).ready(function(){
...
$(".recommend").on('click', function() {
if(confirm("정말로 추천하시겠습니까?")) {
location.href = $(this).data('uri');
}
});
});
</script>
{% endblock %}
pyby/urls.py에 질문 추천 URL 매핑
...
from .views import base_views, question_views, answer_views, comment_views, vote_views
...
urlpatterns = [
...
# vote_views.py
path('vote/question/<int:question_id>/', vote_views.vote_question, name='vote_question'),
]
pybo/views/vote_views.py에 질문 추천 함수 추가
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect
from ..models import Question
@login_required(login_url='common:login')
def vote_question(request, question_id):
# pybo 질문 추천
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)
질문 상세 페이지에 자신의 글 추천시 오류 메시지 표시 기능 추가
...
<div class="container my-3">
<!-- 사용자 요류 표시 Start-->
{% if messages %}
<div class="alert alert-danger my-3" role="alert">
{% for message in messages %}
<strong>{{ message.tags }}</strong>
<ul><li>{{ message.message }}</li></ul>
{% endfor %}
</div>
{% endif %}
<!-- 사용자 오류 표시 End -->
...
질문 추천 기능 확인


질문 상세 페이지에 답변 추천 버튼 생성
<!--답변 내용 영역-->
<h5 class="border-bottom my-3 py-2">
{{ question.answer_set.count }}개의 답변이 있습니다.
</h5>
{% for answer in question.answer_set.all %}
<div class="row my-3">
<!-- 추천 영역 Start -->
<div class="col-1">
<div class="bg-light text-center p-3 border font-weight-bolder mb-1">
{{ answer.voter.count }}
</div>
<a href="#" data-uri="{% url 'pybo:vote_answer' answer.id %}" class="recommend btn btn-sm btn-secondary btn-block my-1">추천</a>
</div>
<!-- 추천 영역 End -->
<div class="col-11">
<div class="card my-3">
...
</div>
</div>
</div>
pybo/urls.py에 답변 추천 URL 매핑
...
urlpatterns = [
...
# vote_views.py
path('vote/question/<int:question_id>/', vote_views.vote_question, name='vote_question'),
path('vote/answer/<int:answer_id>/', vote_views.vote_answer, name='vote_answer'),
]
pybo/views/vote_views.py에 답변 추천 함수 작성
...
from ..models import Question, Answer
...
@login_required(login_url='common:login')
def vote_answer(request, answer_id):
# pybo 답변 추천
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)
답변 추천 기능 확인


질문 목록 페이지 수정
...
<thead class="text-center table-dark">
<tr>
...
<th>추천</th>
...
</tr>
</thead>
<tbody>
...
<tr class="text-center">
...
<!-- 게시물 추천 수 표시 Start -->
<td>
{% if question.voter.all.count >= 0 %}
<span class="badge bg-warning ps-2 py-1">
{{ question.voter.all.count }}
</span>
{% endif %}
</td>
<!-- 게시물 추천 수 표시 End -->
...
질문 목록 페이지에서 추천 확인