이전포스트
[Django] 1. 개발 환경 설정 https://wroni.tistory.com/4
[Django] 2 - 1. URL과 View https://wroni.tistory.com/5
[Django] 2 - 2. 모델 https://wroni.tistory.com/6
[Django] 2 - 3. 장고 관리자 https://wroni.tistory.com/7
[Django] 2 - 4. 조회와 템플릿 https://wroni.tistory.com/8
[Django] 2 - 5. URL과 네임스페이스, 2 - 6. 데이터 저장 https://wroni.tistory.com/9
[Django] 2 - 7. 스태틱 https://wroni.tistory.com/10
[Django] 2 - 8. 부트스트랩 https://wroni.tistory.com/11
[Django] 2 - 9. 템플릿 상속 https://wroni.tistory.com/12
[Django] 2 - 10. 폼 https://wroni.tistory.com/13
[Django] 3 - 1. 네비게이션바 https://wroni.tistory.com/14
[Django] 3 - 2. 페이징 https://wroni.tistory.com/15
[Django] 3 - 3. 템플릿 필터, 3 - 4. 답변 개수 표시 https://wroni.tistory.com/16
[Django] 3 - 5. 로그인과 로그아웃 https://wroni.tistory.com/18
[Django] 3 - 6. 계정생성 https://wroni.tistory.com/19
3 - 7. 모델 변경
게시판의 질문과 답변에는 "글쓴이" 항목이 필요하다.
이번에는 Question과 Answer 모델에 "글쓴이"에 해당하는 author 속성을 추가할 것이다.
1. Question 속성 추가
먼저 Question에 author 속성을 추가할 것이다.
파일 : C:\projects\mysite\pybo\models.py
from django.db import models
from django.contrib.auth.models import User
class Question(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
(...생략...)
author 필드는 User 모델을 ForeignKey 적용하여 선언하였다. User 모델은 django.contrib.auth 앱이 제공하는 사용자 모델이다.
on_delete=models.CASCADE 는 계정이 삭제되면 이 계정이 작성한 질문을 모두 삭제하도록 하는 것이다.
author 속성에 지정해야하는 사용자 객체는 로그인 후 request 객체를 통해 얻을 수 있다.
모델 변경 후에는 makemigrations 와 migrate를 통해 데이터베이스를 변경해주어야 한다.
이제 makemigrations을 실행해보자.
python manage.py makemigrations
makemigrations을 실행하면 option을 선택하라는 위와 같은 메세지가 나타난다.
Question 모델에 author을 추가하면 이미 등록되어 있던 게시물에 author에 해당되는 값이 저장되어야 하는데,
장고는 author에 어떤 값을 넣어야 하는지 모르기 때문이다.
그래서 장고가 기존에 저장된 Question 모델 데이터의 author에 어떤 값을 저장해야 하는지 묻는 것이다.
이 문제를 해결하기 위한 방법으로 2가지가 있다.
첫번째로, author 속성을 null로 설정한다.
두번째로, 기존 게시물에 추가될 author에 강제로 임의 계정 정보를 추가하는 방법이다.
질문, 답변에는 author 값이 무조건 있어야 한다. 그러므로, 두번째 방법을 사용하자.
위의 메세지를 유지한 상태로 1을 입력한다.
그리고 파이썬 셸이 기동되고 >>> 프롬프트가 나타나면, 여기서 다시 1을 입력한다.
여기서 입력한 1은 admin 계정의 id 값인데, 기존 게시물의 author에는 admin 계정이 등록된다.
계정을 생성할 때마다 id가 1부터 순차적으로 증가한다.
따라서 최초에 createsuperuser로 최초 생성했던 계정인 admin의 id 값은 1이다.
이제 migrate를 해서 변경된 내용을 데이터베이스에 적용하자.
python manage.py migrate
2. Answer 속성 추가
이번엔 Question 모델과 같은 방법으로 Answer 모델에 author 속성을 추가하자.
파일 : C:\projects\mysite\pybo\models.py
(...생략...)
class Answer(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
(...생략...)
이어서 makemigrations 명령을 실행하면 다음처럼 Question 모델과 동일한 선택 메세지가 나타난다.
역시 동일 방법으로 1을 선택하고, admin의 id 값인 1을 입력한다.
이어서 migrate 명령을 실행한다.
Answer 모델도 잘 변경되었다.
3. author 저장
이제 Question, Answer 모델에 author 속성이 추가되었으므로 질문과 답변 저장시에 author도 함께 저장해야 한다.
먼저 answer_create 함수를 수정하자.
파일 : C:\projects\mysite\pybo\views.py
(...생략...)
def answer_create(request, question_id):
(...생략...)
if form.is_valid():
answer = form.save(commit=False)
answer.author = request.user # author 속성에 로그인 계정 저장
(...생략...)
답변의 글쓴이는 현재 로그인한 계정이므로 answer.author = request.user 로 처리한다.
request.user 는 현재 로그인한 계정의 User 모델 객체이다.
question_create 함수도 같은 방법으로 수정한다.
파일 : C:\projects\mysite\pybo\views.py
def question_create(request):
(...생략...)
if form.is_valid():
question = form.save(commit=False)
question.author = request.user # author 속성에 로그인 계정 저장
(...생략...)
질문의 글쓴이도 현재 로그인한 계정이므로 question.author = request.user 로 처리한다.
4. 로그인이 필요한 함수
만약 로그아웃 상태에서 질문 혹은 답변을 등록하면 다음과 같이 ValueError가 발생한다.
해당 오류는 request.user가 객체가 아닌 AnonymousUser 객체라서 발생한다.
request.user에는 로그아웃 상태면 AnonymousUser 객체가, 로그인 상태면 User 객체가 들어있다.
앞서 author 속성을 정의할 때는 User를 이용하도록 하였다.
그래서 answer.author = request.user에서 User 대신 AnonymousUser가 대입되어 오류가 발생하였다.
이 문제를 해결하기 위해서는 request.user를 사용하는 함수에 @login_required 애네테이션을 사용해야 한다.
@login_required 어노테이션이 붙은 함수는 로그인이 필요한 함수를 의미한다.
파일 : C:\projects\mysite\pybo\views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .forms import QuestionForm, AnswerForm
from .models import Question
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 qustion_create(request):
(...생략...)
answer_create 함수와 question_create 함수는 함수내에서 request.user를 사용하므로 로그인이 필요한 함수이다.
따라서 위와 같이 @login_required 어노테이션을 사용해야 한다.
로그아웃 상태에서 @login_required 어노테이션이 적용된 함수가 호출되면 자동으로 로그인 화면으로 이동한다.
@login_required 어노테이션은 login_url='common:login' 처럼 로그인 URL을 지정할 수 있다.
이렇게 수정하고 로그아웃 상태에서 질문을 등록하거나 답변을 등록하면 자동으로 로그인 화면으로 이동될 것이다.
5. next
로그아웃 상태에서 '질문 등록하기'를 눌러 로그인 화면으로 전환된 상태에서 웹 브라우저의 URL을 보면 next 파라미터가 있을 것이다.
이것은 로그인 성공 후 next 파라미터에 있는 URL 페이지로 이동하겠다는 의미이다.
하지만 지금을 그렇게 실행되고 있지 않다.
로그인 후 next 파라미터에 잇는 URL로 이동하려면 로그인 템플릿에 gidden 타입의 next 항목을 추가해야 한다.
파일 : C:projects\mysite\templates\common\login.html
(...생략...)
<form method="post" class="post-form" action="{% url 'common:login' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}"> <!--로그인 성공 후 이동되는 url -->
{% include "form_errors.html" %}
(...생략...)
로그인 후 next 항목의 URL로 이동하는 것을 확인할 수 있다.
6. disabled
현재 질문 등록은 로그아웃 상태에서는 아예 글을 작성할 수 없다. 하지만 답변 등록은 로그아웃 상태에서도 글을 작성할 수 있다.
답변 작성 후 <저장하기>를 누르면 자동으로 로그인 화면으로 이동되므로 큰 문제는 아니지만 작성한 답변이 사라진다.
작성한 글이 사라지는 문제를 해결하려면 로그아웃 상태에서는 아예 답변 작성을 못하게 막는 것이 좋다.
pybo/question_detail.html 파일을 수정하자.
파일 : C:\projects\mysite\templates\pybo\question_detail.html
(...생략...)
<div class="form-group">
<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">
(...생략...)
로그인 상태가 아닌 경우 textarea 태그에 disabled 속성을 적용하여 입력을 못하게 하였다.
{% if not user.is_authenticated %} 태그는 현재 사용자가 로그아웃 상태인지를 체크하는 태그이다.
로그아웃 상태에서 disabled가 적용된 화면이다.
※ 본 내용은 django 공부 기록이며, 점프 투 장고를 참고하였습니다.
https://wikidocs.net/book/4223
점프 투 장고
**점프 투 장고 오프라인 책 출간 !! (2020.12)** * [책 구입 안내](https://wikidocs.net/105844)
wikidocs.net
'Django > Django 기초' 카테고리의 다른 글
[Django] 3 - 9. 수정과 삭제 (0) | 2021.12.15 |
---|---|
[Django] 3 - 8. 글쓴이 표시 (0) | 2021.12.14 |
[Django] 3 - 6. 계정생성 (0) | 2021.12.07 |
[Django] 3 - 5. 로그인과 로그아웃 (0) | 2021.12.06 |
[Django] 3 - 3. 템플릿 필터, 3 - 4. 답변 개수 표시 (0) | 2021.12.06 |