게시판의 질문, 답변에는 누가 글을 작성했는지 알려주는 "글쓴이" 항목이 필요하다. Question과 Answer 모델에 "글쓴이"에 해당되는 author 속성을 추가하고자 한다.
1. Question테이블에 속성 추가하기
from django.db import models
from django.contrib.auth.models import User
class Question(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
(... 생략 ...)
- User 모델 : django.contrib.auth 앱이 제공하는 사용자 모델로 회원 가입시 데이터 저장에 사용한 모델이다.
- CASCADE : 계정이 삭제되면 이 계정이 작성한 질문을 모두 삭제하라는 의미이다.
모델을 변경했으니 makemigrations을 실행해야 한다.
python manage.py makemigrations
위와 같이 옵션을 선택하라는 메시지가 나온다.
이 메시지가 나타난 이유는 Question 모델에 author를 추가하면 이미 등록되어 있던 게시물에 author에 해당되는 값이 저장되어야 한다. 장고는 author에 어떤 값을 넣어야 하는지 모르기 때문이다. 그래서 장고가 기존에 저장된 Question 모델 데이터의 author에 어떤 값을 저장해야 하는지 묻는 것이다.
이 문제를 해결하는 방법에는 2가지가 있다.
- author 속성을 null로 설정한다.
- 기존 게시물에 추가될 author에 강제로 임의 계정 정보를 추가한다.
1번을 선택했더니 위와 같이 나왔다. 이를 실제 데이터에 반영하도록 하자.
python manage.py migrate
반영이 잘되었다고 떴다. 이대로 Answer도 똑같은 단계로 하면 된다.
author 속성에 null 허용하기
추가한 author 속성에 null을 허용하려면 다음처럼 null=True 속성을 추가하면 된다.
Copyauthor = models.ForeignKey(User, on_delete=models.CASCADE,null=True)
2. author 저장하기
위에서는 기존에 있던 데이터에 author를 추가했을 때 null로 저장해줬다. 이제는 질문, 답변
에 author과 같이 저장해야 한다.
// pybo/views.py
def answer_create(request, question_id):
(... 생략 ...)
if form.is_valid():
answer = form.save(commit=False)
answer.author = request.user # author 속성에 로그인 계정 저장
(... 생략 ...)
(... 생략 ...)
- request.user는 현재 로그인한 계정의 User 모델 객체로, 로그인한 사용자를 저장되게 하였다.
question_create도 똑같이 수정해준다.
3.로그인이 필요한 함수 지정하기
위에서 author를 저장할 때 로그인한 유저로 저장되게 설정하였다. 그래서 질문과 답변을 달 때 로그인을 해야 한다. 그렇지 않으면 User 대신 AnonymousUser가 대입되어 오류가 발생한다.
이를 해결하기 위해 어노테이션을 사용해준다.
// pybo/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Question
from .forms import QuestionForm, AnswerForm
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
(... 생략 ...)
@login_required(login_url='common:login')
def answer_create(request, question_id):
(... 생략 ...)
@login_required(login_url='common:login')
def question_create(request):
(... 생략 ...)
로그아웃 상태에서 @login_required 어노테이션이 적용된 함수가 호출되면 자동으로 로그인 화면으로 이동하게 된다. @login_required 어노테이션은 login_url='common:login' 로그인 URL을 지정할 수 있다. 질문을 등록해서 로그인 화면으로 전환된 상태에서 웹 브라우저 주소창의 URL을 보면 next 파라미터가 있는 것을 볼 수 있다.
여기서 next 파라미터에 있는 URL로 페이지는 로그인 성공 후에 이동되는 페이지를 말한다. 그런데 지금 봤을 때 next 파라미터 뒤에 아무것도 존재하지 않는다.
// common/login.html
(... 생략 ...)
<form method="post" action="{% url 'common:login' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}"> <!-- 로그인 성공후 이동되는 URL -->
{% include "form_errors.html" %}
(... 생략 ...)
4. disabled 등록하기
로그아웃 상태에서 질문과 답변을 등록할려고 하면 로그인 화면으로 전환되는 바람에 이전에 작성된 글들이 날아간다. 그래서 아예 로그아웃 상태에서 답변 작성을 하지 않도록 수정할 것이다.
// pybo/question_detail.html
(... 생략 ...)
<div class="mb-3">
<label for="content" class="form-label">답변내용</label>
<textarea {% if not user.is_authenticated %}disabled{% endif %}
name="content" id="content" class="form-control" rows="10"></textarea>
</div>
<input type="submit" value="답변등록" class="btn btn-primary">
(... 생략 ...)
{% if not user.is_authenticated %} 태그는 현재 사용자가 로그아웃 상태인지를 체크하는 태그이다. 아래와 같이 로그인이 되지 않았다면 disabled된다.
위와 같은 상태에서 답변 등록 버튼을 누르게 되면 로그인 화면으로 이동되게 된다.