GDSC HUFS 3기/Backend - Django

[Django] 3주차_2_ 파이보 서비스 개발4

qkrgusqls 2022. 5. 29. 14:18

이 글은 점프 투 장고를 참고하여 작성하였습니다.

작성자 : 박현빈

개발환경은 Python, PyCharm입니다. 

3 - 11) 추천 

 

Question 모델에 voter(추천인) 속성을 추가

voter = models.ManyToManyField(User)  # 추천인 추가

 

추천인을 추가했을때, makemigrations 실행시 author와 voter 모두 User 모델과 연결되어 있어 오류 발생

 

(mysite) c:\projects\mysite>python manage.py makemigrations
SystemCheckError: System check identified some issues:

ERRORS:
pybo.Question.author: (fields.E304) Reverse accessor 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 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'.

(mysite) c:\projects\mysite>

 

Question과 Answer 모델에 related_name을 추가

some_user.author_question.all() ,some_user.voter_question.all() 처럼 사용 가능! 

 

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')

    def __str__(self):
        return self.subject

makemigrations, migrate 실행시 오류 없이 수행 

질문 추천 기능 

1. 추천 버튼 만들기, 추천 버튼 확인창 만들기

<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>

추천 버튼 

const recommend_elements = document.getElementsByClassName("recommend");
Array.from(recommend_elements).forEach(function(element) {
    element.addEventListener('click', function() {
        if(confirm("정말로 추천하시겠습니까?")) {
            location.href = this.dataset.uri;
        };
    });
});

추천 버튼 확인 창 

 

2. url 매핑 규칙 추가 

urlpatterns = [
    (... 생략 ...)
    path('question/vote/<int:question_id>/', question_views.question_vote, name='question_vote'),
]

3. views.py question_vote 함수 수정 

@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)

답변 추천도 같은 패턴으로 실행 

 

3 - 12) 앵커 

: 답글을 작성, 수정한 후에 항상 페이지 상단으로 스크롤이 이동되기 때문에 본인이 작성한 답변을 확인하려면 다시 스크롤을 내려서 확인해야 한다는 점을 해결 하기 위한 방법 

 

HTML에는 URL 호출시 원하는 위치로 이동시켜 주는 앵커(anchor) 태그 존재, 이를 활용하여 해결 

 

1. 상세 템플릿에 앵커 태그 추가 

2. 태그로 이동하도록 views.py 파일 수정

return redirect('{}#answer_{}'.format(
    resolve_url('pybo:detail', question_id=question.id), answer.id))

resolve_url은 실제 호출되는 URL 문자열을 리턴하는 장고의 함수이다.

 

3 - 13) 마크다운

질문이나 답변을 작성할 때 일반적인 텍스트 외에 글자를 진하게 표시하거나 링크를 추가할 때, '마크다운'이라는 글쓰기 도구를 이용

3 - 14) 검색

1. 검색창을 템플릿 파일에 추가 , 페이징 기능 추가 

2. 검색 함수 추가 

from django.db.models import Q
(... 생략 ...)

def index(request):
    page = request.GET.get('page', '1')  # 페이지
    kw = request.GET.get('kw', '')  # 검색어
    question_list = Question.objects.order_by('-create_date')
    if kw:
        question_list = question_list.filter(
            Q(subject__icontains=kw) |  # 제목 검색
            Q(content__icontains=kw) |  # 내용 검색
            Q(answer__content__icontains=kw) |  # 답변 내용 검색
            Q(author__username__icontains=kw) |  # 질문 글쓴이 검색
            Q(answer__author__username__icontains=kw)  # 답변 글쓴이 검색
        ).distinct()
    paginator = Paginator(question_list, 10)  # 페이지당 10개씩 보여주기
    page_obj = paginator.get_page(page)
    context = {'question_list': page_obj, 'page': page, 'kw': kw}
    return render(request, 'pybo/question_list.html', context)